Files
mnote/bugs/07-ai/done/7-27-markdown-edit-full-content-retains-old-blocks-v1.md
lix-2026 a2cb1338c8 chore: 保存当前架构收口与 bug 修复快照
归档本轮 P0/P1 bug 修复、设计审查迁移、AI selection scope 收口与 stream contract 调整,并保留当前 05 主线迁移起点。
2026-05-18 17:01:35 +08:00

3.3 KiB
Raw Permalink Blame History

7-27 [done][bug] 在线 markdown_edit full_content 会保留旧普通块

发现时间:2026-05-18

状态:[done]

关联主线:07-ai

关联设计:design/07-ai/process/7-27-online-markdown-writeback-final-content-truth-v2.md

1. 问题定义

mnote.doc.markdown_edit 的在线 Convex 文档路径已经切到 final markdown -> block content 直接写回,但 full_content 模式下,最终 markdown 通常不包含任何 <!-- block:... --> 原始块注释。

当前 build_page_content() 会把所有未处理的原始块追加到写回结果尾部,导致全文替换不是“替换全文”,而是:

新全文块...
旧 heading / paragraph / todo 块...

2. 影响

  • AI 执行全文改写、重写大纲、把页面替换为整理后的内容时,会保留旧正文残留。
  • Page Aggregate / mnote.doc.fetch 回读会看到新旧内容混在一起。
  • 7-27 的“最终 markdown 是唯一写回真源”合同被破坏。

3. 根因

parse_final_markdown_to_blocks() 对无注释的 final markdown 行会生成 is_new=true 块,这是正确的。

问题在 build_page_content() 的末尾:

for original in &original_blocks {
    if let Some(id) = block_id_of(original) {
        if !processed_ids.contains(&id) {
            result.push(original.clone());
        }
    }
}

该逻辑没有区分:

  • 部分 search/replace 丢掉某个块注释:应保守保留缺失旧块,避免误删。
  • full_content / 全文替换没有任何原始块 ID:应只保留复杂块,普通旧文本块应被替换掉。

4. 修复

  • doc.rsbuild_page_content() 增加策略:
    • 若 parsed 中至少引用了一个原始 block id,则保留未处理原始块,维持安全降级。
    • 若 parsed 中没有任何原始 block id,则视为全文重建,只保留复杂块,不保留普通旧文本块。
  • doc.rs 增加 is_complex_markdown_original_block(),用于 full_content 重建时保留 resource / mindmap / table / image / attachment / 非 editable / unsupported / 带 children 的复杂块。
  • doc.rs 增加单元测试:
    • full_content 无原始 ID 时不保留旧 heading / paragraph。
    • 原始 resource 复杂块仍保留。
    • 部分块注释丢失时仍保留缺失旧块。

5. 验证

cargo test --manifest-path rust/Cargo.toml -p mnote-web build_page_content -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_online_full_content_rejects_unsafe_block_mapping -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit -- --nocapture
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
git diff --check -- rust/crates/mnote-web/src/hermes_tools/doc.rs bugs/07-ai/done/7-27-markdown-edit-full-content-retains-old-blocks-v1.md

结果:

  • build_page_content 相关测试:2 passed
  • hermes_tools_markdown_edit_online_full_content_rejects_unsafe_block_mapping1 passed
  • hermes_tools_markdown_edit 相关测试:6 passed
  • Rust workspace format check 通过。
  • 相关路径 diff check 通过。