# 5-19 [done] Page Aggregate 块投影未优先消费 EditorBlockDocument

## 级别

P1 / 05-editor-mainline 主线迁移缺陷。

## 现象

`page.body.save` 已在 Rust runtime plan 与 artifact 中保留 `editorDocument`，但 `page.aggregate.get` 构建 `body.blockDocument` 时仍固定从 legacy `documents.content` 投影。

当 `editorDocument` 与旧 `content` 不一致时，AI 块读取、块定位与 Page Aggregate 回读会继续看到旧内容，导致页面域单一真源迁移停留在 legacy content 过渡层。

## 根因

`rust/crates/bridge-runtime/src/lib.rs` 的 `build_page_aggregate_projection_result` 只读取 `content_result.content`，随后调用 `project_legacy_content_to_block_document`，并把 `projectionSource` 固定为 `documents.content`。

## 修复

- `page.aggregate.get` 的内容结果识别现在包含 `editorDocument` 与 `blockDocument`。
- Page Aggregate `body.blockDocument` 来源顺序调整为：
  - `editorDocument`：优先解析 `EditorBlockDocument`，由 Rust runtime 投影为 Page Aggregate 块文档。
  - `blockDocument`：已有块投影直接作为次级来源。
  - `documents.content`：仅在缺少原生块文档来源时回退。
- `body.projectionSource` 改为真实来源：`editorDocument` / `blockDocument` / `documents.content`。
- 新增回归测试 `page_aggregate_get_prefers_editor_document_over_legacy_content`，覆盖 `editorDocument` 与旧 `content` 冲突时的优先级。
- 新增非法原生块文档防回退保护：
  - `editorDocument` 存在但不可解析时返回 validation error，不再静默回退到旧 `content`。
  - `blockDocument` 存在但不是对象时返回 validation error，不再静默回退到旧 `content`。
- Page Aggregate `body.content` 也同步按原生来源重建：
  - `editorDocument` 来源下由 `EditorBlockDocument` 生成 legacy content。
  - `blockDocument` 来源下由块投影生成 legacy content。
  - 避免同一份 Page Aggregate 中 `body.blockDocument` 正确但 `body.content` 仍指向旧正文，导致编辑器/session 下游继续显示或保存旧真相。

## 验证

- RED：`cargo test --manifest-path rust/Cargo.toml -p bridge-runtime page_aggregate_get_prefers_editor_document_over_legacy_content -- --nocapture`
  - 旧实现失败，返回 `legacy_1` 而不是 `editor_1`。
- GREEN：`cargo test --manifest-path rust/Cargo.toml -p bridge-runtime page_aggregate -- --nocapture`
  - 6 passed。
- Rust Web 回归：`cargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregate -- --nocapture`
  - 7 passed。
- 格式：`cargo fmt --manifest-path rust/Cargo.toml --all -- --check`
  - passed。

## 剩余边界

这次修的是 Page Aggregate 读侧优先级，不是 Convex 原生 `EditorBlockDocument` 落库 schema 的最终切换。`documents:updateContent` 兼容写入仍保留 legacy content substrate；后续主线应继续推进持久层原生块文档字段与命令写入闭环。
