- add npm dev:hot wrapper using cargo-watch and page reload polling - add mnote-web dev hot reload endpoint and coverage - record current architecture review and tracked bug findings across realtime, tree, editor, and AI runtimes Verification: - node scripts/task-dev-hot-plan-test.js - node --check scripts/dev-hot.js - cargo test -p mnote-web dev_hot -- --nocapture
5.0 KiB
10 [process] 当前 mnote 项目 AI / Page Aggregate 定向 Review v1
更新时间:2026-05-17
执行状态:
process范围:当前主线中 Page Aggregate 单一真源、页面 AI 快速编辑、
mnote.doc.markdown_edit与 ACP / Hermes runtime 的源码级定向审查。
1. 本轮结论
本轮没有发现 Page Aggregate 读取主链重新回退到 Next compat builder 的证据;wolai-frontend/src/lib/documents/page-aggregate-loader.ts 仍只走 Rust /api/page-aggregate/:documentId,/api/documents/page compat 读链保持 410 退场口径。
新的风险集中在 07-ai 的 markdown 编辑收敛实现:
mnote.doc.markdown_edit已进入实际写入主线,并被/api/page-ai/block-edit-workflow调用。- 该工具当前先在 markdown 字符串上顺序执行 search/replace,再把原始 operations 重新转换成
mnote.doc.apply_block_ops。 - 转换层仍按“单块文本包含 search”查找目标块,无法忠实表达 markdown 层已经算出的最终结果。
因此,当前 AI 编辑主线不能只看 operationsApplied > 0 或 route 返回 ok=true。需要优先补充 markdown_edit 的中文、多操作、同块、多块、full_content 与失败原子性测试。
2. 发现的问题
R-01 P0:中文归一化匹配使用 byte index 当 char index
关联缺陷:
bugs/07-ai/process/7-16-markdown-edit-normalized-search-byte-index-v1.md
证据:
rust/crates/mnote-web/src/hermes_tools/doc.rs:920-936
search_replace 的 Level 2 先在 norm_line 上用 find() 得到 UTF-8 byte offset,却把这个 offset 传给 line.char_indices().nth(start) 当作字符序号使用。中文、多字节标点或中英混排时,替换范围会偏移,可能替错片段或生成错误内容。
影响:
- 页面 AI 对中文正文的“忽略空白 / 全半角差异”替换不可靠。
- 该问题位于
mnote.doc.markdown_edit的基础 search/replace 层,会同时影响在线文档和本地.md文件。
R-02 P0:同一块内多次 markdown_edit 会被后续 block op 覆盖
关联缺陷:
bugs/07-ai/process/7-17-markdown-edit-same-block-multi-op-overwrite-v1.md
证据:
rust/crates/mnote-web/src/hermes_tools/doc.rs:779-824rust/crates/mnote-web/src/hermes_tools/doc.rs:854-878rust/crates/mnote-web/src/hermes_tools/doc.rs:976-1008
doc_markdown_edit 已经在 md 变量中顺序应用了所有 search/replace,但 Convex 写入时没有使用这个最终 markdown。它重新读取原始 Page Aggregate blocks,并对每个 operation 用原始 block 文本生成一个 replace block op。
如果两个 operation 命中同一个 block,第二个 block op 的 content 仍从原始文本计算,会覆盖第一个 operation 的结果。也就是说,markdown 层算出的最终结果与实际落库结果可能不一致。
影响:
- AI 一次请求中常见的“把同一段里的 A 改成 B,同时把 C 改成 D”可能只保留最后一次修改。
- 前端快路径仍可能显示“已通过页面 markdown 编辑快路径完成写入”,但正文只部分生效。
3. 次级风险
doc_markdown_edit当前允许部分 operation 失败后继续写入已成功的子集,并返回ok=true。如果这是有意设计,需要在 manifest / UI 中明确“非原子”;如果不是,应改为任一 operation 失败时不写入。changedText通过operations.iter().take(applied)生成摘要;当前如果第一个 operation 失败、第二个成功,摘要会错误地展示第一个失败 operation。/api/page-ai/block-edit-workflow的系统 prompt 已改成 search/replace,但仍强依赖模型精确复制pageText;一旦模型输出跨块片段,Convex 写回层不能表达该编辑。
4. 建议下一步
- 先给
search_replace补中文归一化替换单测,再修正 byte / char offset 映射。 - 给
doc_markdown_edit补同一 block 多 operation 的失败用例,明确应以最终 markdown 生成落库内容,或在转换层合并同块操作。 - 明确
markdown_edit的失败原子性:默认建议任一 operation 失败时不写入,除非请求显式允许 partial apply。 - 将
/api/page-ai/block-edit-workflow的验收从“route 成功”提升为“Page Aggregate 回读与预期最终 markdown 一致”。
5. 本轮验证
静态检查范围:
rg -n "markdown_edit|apply_block_ops|block-edit-workflow|local_rule|page_ai_workflow|mnote\\.doc\\.fetch" rust wolai-frontend scripts design/07-ai design/10-review --glob '!rust/target/**' --glob '!node_modules/**'
rg -n "page-aggregate|pageAggregate|PageAggregate|blockDocument|projectionSource|documents/save|documents/options|/api/page-aggregate" rust/crates/mnote-web rust/crates/bridge-runtime wolai-frontend/src scripts --glob '!rust/target/**' --glob '!node_modules/**'
本轮是 review / bug hunt,没有修改 runtime 源码。后续修复应至少补:
cargo test --manifest-path rust/Cargo.toml -p mnote-web markdown_edit
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_workflow