归档本轮 P0/P1 bug 修复、设计审查迁移、AI selection scope 收口与 stream contract 调整,并保留当前 05 主线迁移起点。
3.3 KiB
3.3 KiB
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.rs 给
build_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_mapping:1 passed。hermes_tools_markdown_edit相关测试:6 passed。- Rust workspace format check 通过。
- 相关路径 diff check 通过。