# 5-36 Page Aggregate local-first hard guard v1

> 创建时间：2026-06-07
>
> 状态：`done`
>
> Owner：05-editor-mainline
>
> 上位 checklist：`design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P3

## 1. 目标

防止 local-first `.md` 文档页静默回落到 `compat.legacy_content` 影子正文路径。local folder 的正常读链必须是：

1. 本地 Markdown 文件是真相。
2. Rust Page Aggregate 输出 `body.projectionSource=local_markdown.content`。
3. Page Aggregate 输出 `body.blockDocument`。
4. 浏览器 tiptap runtime 优先消费 `page_aggregate.block_document`。

## 2. 非目标

- 不删除 cloud / legacy / explicit compat 的 `compat.legacy_content` fallback。
- 不改写 Page Aggregate 保存命令族。
- 不扩大 legacy blocks / `documents.content` 的 local-first 使用面。

## 3. Checklist

- [x] 复核 `document-tiptap-conversion-runtime.js` source 判定：`blockDocument` 优先于 `content`。
- [x] 给文档 editor root 增加 DOM diagnostic：
  - `data-mnote-page-body-source`
  - `data-mnote-page-body-local-compat-fallback`
  - `data-mnote-page-body-hard-guard`
- [x] local-first browser smoke 断言 `.md` 文档页为 `page_aggregate.block_document`，且 `local-compat-fallback=false`。
- [x] `task522` contract 保留 explicit compat fallback 正例。
- [x] `task167` API smoke 继续证明 local-first Page Aggregate 输出 `local_markdown.content` + `blockDocument`。

## 4. 验证结果

- `node scripts/task522-page-aggregate-compat-fallback-contract.js` 通过。
- `node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js` 通过。
- `node scripts/task541-page-aggregate-local-first-hard-guard-smoke.js` 通过：真实浏览器打开 local `.md`，editor root 诊断为 `data-mnote-page-body-source=page_aggregate.block_document`、`data-mnote-page-body-local-compat-fallback=false`、`data-mnote-page-body-hard-guard=local_ok`。
- `cargo test -p mnote-web document_editor_adapter_runtime_contains_host_contracts -- --test-threads=1` 通过。

## 5. 归档条件

- [x] `design/10-review/done/20-post-lightrag-runtime-hardening-checklist-v1.md` P3 全部勾选。
- [x] P3 targeted smoke 和 contract test 通过。
- [x] CodeGraph 同步无 pending。
