# 7-24 [done][bug] 在线 markdown_edit 写回不以最终 Markdown 为真源 v1

> 发现时间：2026-05-17
>
> 状态：`[done]`
>
> 关联主线：`07-ai`

## 1. 问题定义

在线 Convex 文档的 `mnote.doc.markdown_edit` 先在 `md` 字符串上顺序应用 search/replace，但写回时没有用最终 `md` 生成新的文档真相，而是重新读取原始 blocks，并用原始 operations 反推 `apply_block_ops`。

因此 markdown 层已经算出的最终结果不一定能被忠实落库。

## 2. 证据

- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:811) 在 `md` 上执行 search/replace。
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:855) 写回前重新读取 aggregate / blocks。
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:857) 使用原始 operations 构造 block ops，而不是解析最终 `md`。

## 3. 影响

- 跨块替换、全文替换、标题 / 列表格式变化可能在 markdown 层成功，但无法正确转换成 block ops。
- 部分失败仍可能返回成功写入，用户看到的正文与工具返回摘要不一致。
- 该问题与 `7-17` 的同块多操作覆盖同源，但影响面更宽。

## 4. 建议修复

- 在线分支应明确选择一种真源：要么最终 `md` 可被解析并完整生成 EditorBlockDocument，要么限制 `markdown_edit` 只支持可安全映射的单块操作。
- 对 full_content、跨块 search/replace、列表/标题变更增加回读一致性测试。
- route 成功条件必须从“operationsApplied > 0”提升为“Page Aggregate 回读等于预期最终 markdown”。

## 5. 修复

- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:868) 在线分支在 markdown 层命中后重新映射为 block ops；若最终 markdown 变化无法安全映射到可写块，会返回 `mnote_doc_markdown_edit_block_mapping_empty`，不再把空 operations 交给 `apply_block_ops` 或返回伪成功。
- [hermes_tools.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_tools.rs:1857) 增加 `full_content` 在线写回合同测试：当前没有完整 markdown->block 真源写回时必须明确拒绝，不能以 `ok=true` 伪成功。
- [hermes_tools.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_tools.rs:1805) 保留 markdown 命中但块映射为空的提前失败测试，避免回退到 `mnote.doc.apply_block_ops operations 不能为空`。

## 6. 验证

- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_online_full_content_rejects_unsafe_block_mapping -- --nocapture`
  - 结果：1 passed
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web markdown_edit -- --nocapture`
  - 结果：8 passed
