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

3.1 KiB
Raw Blame History

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_scope1 passed
  • block_edit_workflow_forwards_allowed_target_blocks_to_markdown_edit1 passed
  • Rust workspace format check 通过。