# 7-51 mindmap apply_ops 结构化写入与可见性缺口 ## 状态 - 状态:done,工具层最小结构化写入、刷新后 embedded mindmap id 保真、真实 mindmap resource tab Page AI target 已修复;更丰富 `apply_ops` 指令面扩展另拆 follow-up,不阻塞本 bug 归档 - Owner:07-ai / Hermes tools / mindmap resource - 发现时间:2026-06-01 ## 现象 `mnote.mindmap.apply_ops` 的非 dry-run 路径曾不执行结构化写入,而是在完成资源路径和写权限校验后返回 `mnote_resource_native_patch_required`,提示 agent 使用原生 patch 编辑授权文件。这与 `7-42` 第二批目标“把 `apply_ops` 从提示 agent patch 文件收口到结构化写入”不一致。 2026-06-01 本轮已完成工具层最小修复:`dryRun=false` 可执行 `updateText` / `updateNode`、`insertChild` / `addChild`、`deleteNode`,写入后返回 `revision`、`changedFiles`、`markdownSummary`,并保留 `view`、未知顶层字段和未知 node 字段。当前缺口转为浏览器可见性和 Page AI resource target 集成。 ## 证据 - `rust/crates/mnote-web/src/hermes_tools/resource.rs` 的 `mindmap_apply_ops()` 已实现最小结构化写入。 - `rust/crates/mnote-web/src/routes/hermes_tools.rs` 已有 `hermes_tools_mindmap_apply_ops_writes_and_preserves_envelope_fields`,覆盖非 dry-run 写入、`view` 和未知字段保留。 - `rust/crates/mnote-web/src/routes/hermes_tools.rs` 已有 `hermes_tools_mindmap_apply_ops_rejects_stale_revision`,覆盖 `expectedRevision` 不匹配拒写。 - `rust/crates/mnote-web/src/routes/hermes_tools.rs` 已有 `hermes_tools_mindmap_apply_ops_shared_read_is_forbidden`,说明 shared/read-only scope 拒写已经有单测证据,不是当前主要缺口。 - `task455`、`task524`、`task525` 已覆盖 embedded mindmap 刷新、FileTree / Resource Tab 可见性和真实 Page AI mindmap target/contextRefs。 ## 影响 - Agent 已可通过结构化 tool 安全执行最小增删改 mindmap node,不再只能回退到文件 patch。 - `view`、未知字段保留和 revision conflict 已由工具层单测覆盖。 - Page AI mindmap 第二批的最小可用链路已覆盖:tool 结构化写入、embedded mindmap 刷新、FileTree / Resource Tab 可见性,以及真实 Page AI mindmap target/contextRefs。后续缺口转为真实编辑需求下的更丰富 `apply_ops` 指令面。 ## 修复建议 - 按真实编辑需求继续扩展 `apply_ops`,例如 `moveNode`、`insertSiblingAfter`、`setHyperlink`、`setRefs`、`appendNote`、`patchView`。 ## 验收 - [x] Rust 单测覆盖 `apply_ops` 非 dry-run 结构化写入。 - [x] Rust 单测覆盖 `view` 和未知字段保留。 - [x] Rust 单测覆盖 revision mismatch 返回 conflict。 - [x] Rust 单测覆盖 shared/read-only scope 下写工具拒绝。 - [x] Browser smoke 覆盖 mindmap 资源在 File Tree / Resource Tab 可见。 - [x] Browser smoke 覆盖真实 mindmap resource tab 注入 Page AI `active_editor` contextRef / `targetPackage`。 - [x] `task455-local-folder-mindmap-clean-smoke.js` 刷新后 `mindmapId` 保持新建资源文件名,不退化为 `"mindmap"`。 ## 本轮验证 - `cargo test -p mnote-web hermes_tools_mindmap_apply_ops -- --test-threads=1` - `cargo test -p mnote-web mindmap -- --test-threads=1` - 2026-06-01 复跑失败:`MNOTE_UI_BASE_URL=http://127.0.0.1:3301 node scripts/task455-local-folder-mindmap-clean-smoke.js` - 失败点:`刷新后 mindmapId 应保持不变` - 证据:`tmp/task455-local-folder-mindmap-clean-smoke/result.json` - 关键现象:刷新前 `mindmapId=mindmap-647356316`,刷新后 DOM `mindmapId=mindmap`;FileTree 仍有 `local-file:CleanPage/mindmap-647356316.json` 行。 - 2026-06-01 修复后复跑通过:`MNOTE_UI_BASE_URL=http://127.0.0.1:3301 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3301 node scripts/task455-local-folder-mindmap-clean-smoke.js` - 修复点:`blockDocument.blocks[].attrs` 保留 `mindmapId/sourcePath/rootNodeId`,浏览器 `document-tiptap-conversion-runtime.js` 消费 blockDocument 时读取这些 attrs。 - 补充验证:`cargo test -p bridge-runtime page_aggregate_block_document_preserves_mindmap_projection_attrs -- --test-threads=1`,`cargo test -p mnote-web local_markdown_generated_mindmap_id_roundtrips_as_mindmap_block -- --test-threads=1`。 - 回归验证:`MNOTE_UI_BASE_URL=http://127.0.0.1:3301 node scripts/task524-workspace-object-identity-matrix-smoke.js`。 - 2026-06-01 新增并通过:`MNOTE_UI_BASE_URL=http://127.0.0.1:3301 node scripts/task525-page-ai-mindmap-resource-target-smoke.js` - 覆盖真实 local-folder mindmap resource tab 打开后,Page AI run payload 中 `contextRefs.active_editor.resourceKind=mindmap`。 - 覆盖 `targetPackage.primaryTargetId`、`targetPackage.currentFile`、`allowedFiles` 指向 `Page/map.mindmap.json`。