归档本轮 P0/P1 bug 修复、设计审查迁移、AI selection scope 收口与 stream contract 调整,并保留当前 05 主线迁移起点。
3.1 KiB
3.1 KiB
7-28 [done][bug] markdown_edit 未强制 selection 允许块边界
发现时间:2026-05-18
状态:
[done]关联主线:
07-ai
1. 问题定义
页面 AI context 已经可以携带 allowedTargetBlockIds,用于表达 scope=selection 时本次 run 允许修改的块集合。但 mnote.doc.markdown_edit 当前只按文本 search/replace 写回,不检查最终变化的 block 是否落在允许集合内。
如果 fast workflow 或未来调用者传入了过宽的 pageText,模型返回了选区外文本的 search/replace,服务端仍可能写入选区外块。
2. 证据
- page_ai_workflow.rs fast workflow 调用
mnote.doc.markdown_edit。 - page_ai_workflow.rs 读取了
allowedTargetBlockIds,但未传给写工具或参与校验。 - hermes_client.rs 工具指导要求
scope=selection时只能修改allowedTargetBlockIds内的块。 - doc.rs
markdown_edit生成changedBlocks后直接 dry-run 或写回,没有 selection 范围校验。
3. 影响
- 页面 AI 对选中文本执行编辑时,服务端缺少最终兜底边界。
- 上下文构造或模型输出一旦漂移,选区外块可能被写入。
- 与
mnote.block.*已有allowedTargetBlockIds/ blockId 前置条件相比,markdown_edit的写入安全边界较弱。
4. 修复
- page_ai_workflow.rs fast workflow 将
aiContext.allowedTargetBlockIds透传给mnote.doc.markdown_edit。 - doc.rs
mnote.doc.markdown_edit在生成changedBlocks后,如果存在allowedTargetBlockIds/selectedBlockIds:- 任何带
blockId的变更必须属于允许集合。 - 无
blockId的 insert/full_content 变更在 selection scope 下拒绝,避免无法归属的选区外写入。
- 任何带
- hermes_tools.rs 增加 route 测试:
allowedTargetBlockIds=["p_2"]时替换p_1必须返回mnote_markdown_edit_target_out_of_scope。 - page_ai_workflow.rs 增加 fast workflow 测试:模型输出修改
p_1,而 selection 只允许p_2,必须被服务端拒绝。
5. 验证
cargo test --manifest-path rust/Cargo.toml -p mnote-web markdown_edit_rejects_selection_out_of_scope -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web block_edit_workflow -- --nocapture
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
结果:
hermes_tools_markdown_edit_rejects_selection_out_of_scope:1 passed。block_edit_workflow_forwards_allowed_target_blocks_to_markdown_edit:1 passed。- Rust workspace format check 通过。