11 KiB
5-10 [done][bug] 文件树思维导图打开污染 index.md 单一真源 v1
更新时间:2026-05-13
分类归属:
05-editor-mainline/done- 涉及边界:
04-tree-domain/file_tree asset intent、03-rust-web/mindmap standalone shell、06-mindmap/projection editor关联文档:
/mnt/Data1T/mnote/design/10-review/README.md/mnt/Data1T/mnote/design/10-review/02-frontend-editor-tree-review.md/mnt/Data1T/mnote/design/10-review/04-secondary-domains-and-design-governance-review.md/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md/mnt/Data1T/mnote/design/04-tree-domain/done/4-2-sidebar-pagetree-filetree-product-interaction-contract-v1.md/mnt/Data1T/mnote/design/06-mindmap/process/6-mindmap-kernel-phase6-projection-editor-v1.md
1. 问题定义
当前文件树中的思维导图文件点击打开后,会进入 standalone /mindmap/{documentId}/{mindmapId} 壳。这个壳会构造一份只包含单个 mindmap block 的临时 editor bootstrap,而不是读取该页面真实的 index.md / Page Aggregate body。
结果是:用户从文件树打开思维导图、编辑、切换页面后,再点击同一页面的 index.md,可能看到只剩思维导图默认内容的页面体验。这里的核心问题不是单次保存失败,而是 index.md 页面正文与文件树里的 mindmap asset 没有明确收口到同一份页面真源。
2. 归类理由
本问题归到 05-editor-mainline,而不是只归到 06-mindmap,理由如下:
- 用户可见故障发生在文档页壳、文件树点击打开、主编辑区内容切换体验上。
- 受影响对象是
index.md页面正文与主编辑区当前内容,而不只是 mindmap runtime 内部编辑能力。 design/10-review已明确当前 Page Aggregate 仍是“主链已切、单一真源收口未完”的状态,本问题正是页面正文、asset view 与 standalone shell 边界未闭合的具体缺陷。04-tree-domain需要定义 filetree asset row 的 open intent,但真正承载用户体验和页面真源一致性的 owner 仍是编辑主线。
3. 真实现象
用户复现结论:
- 打开文件树中的思维导图文件,编辑后可以正常保存。
- 切换页面后,文件树中的思维导图仍能保存。
- 切换页面后点击文件树中的
index.md,主编辑区只显示思维导图默认内容,而不是该页面真实正文。
用户判断的根因方向:
- 之前对文件树中的思维导图文件点击操作会对主页面产生干扰,应取消该干扰。
- 思维导图文件的点击打开应该在主编辑区弹出新页面或新 tab,类似 VS Code,而不是污染
index.md。 - 当前文件树
index.md与其中的思维导图没有只持有一份真源,需要收口成单一来源。
4. 证据
设计审查证据:
design/10-review/README.md明确当前最需要收口的是Page Aggregate单一真源边界、tree realtime/live cache、side effect 一致性,以及 legacy/compat/fallback 退场边界。design/10-review/02-frontend-editor-tree-review.md的 F-01 指出 Page Aggregate 读链已 Rust-first,但客户端仍有本地 aggregate reducer 持有标题、正文、设置、子树快照等临时真相,页面域单一真源尚未闭环。design/10-review/04-secondary-domains-and-design-governance-review.md的 Mindmap 段落指出 standalone mindmap shell 已存在,但 compat 数据层仍承载导图数据,不应被描述为长期 canonical truth。
代码锚点:
rust/crates/mnote-web/src/ssr/pages/layout.rs:1100定义buildMindmapOpenPath(documentId, assetId),直接生成/mindmap/{documentId}/{assetId}。rust/crates/mnote-web/src/ssr/pages/layout.rs:1128到:1134的openConvexAssetFromFileTree在识别到 mindmap asset 后直接window.location.assign(buildMindmapOpenPath(documentId, assetId))。rust/crates/mnote-web/src/ssr/pages/layout.rs:1180到:1182将tree.asset.open统一交给openConvexAssetFromFileTree。rust/crates/mnote-web/src/ssr/pages/layout.rs:3551到:3555文件树点击index/document/markdown时导航到文档页,但非文档 row 且有assetId时 dispatchtree.asset.open,mindmap asset 因而进入 standalone mindmap 路由。rust/crates/mnote-web/src/routes/mindmap_shell.rs:75到:104standalone mindmap shell 构造临时editor_bootstrap.content,内容只有一个mnoteBlockType: "mindmap"的 paragraph block。rust/crates/mnote-web/src/routes/mindmap_shell.rs:105到:123standalone contract 标记为mnote.mindmap_shell.v1,projection source 仍是compat-blob。wolai-frontend/src/components/sidebar/sidebar-navigation.ts:21到:33的 React 侧buildSidebarMindmapOpenTarget在main模式下返回/documents/{documentId},只有sidebar模式才打开/mindmap/{documentId}/{mindmapId};这说明至少已有一条路径表达了“主编辑区不应直接进入 standalone mindmap shell”的倾向。
5. 当前判断
当前更像是三条路径混在一起:
index.md应代表页面正文,并由 Page Aggregate body / page command 持有。- 文件树中的 mindmap asset 应代表页面内某个 mindmap block 关联的资源视图或编辑入口。
- standalone
/mindmap/{doc}/{mindmap}是过渡兼容壳,应作为独立编辑页或调试/弹出入口,不应替代主编辑区的index.md真源。
因此,即使 mindmap asset 自己可以保存,也不能说明 index.md 与 mindmap block 已经同源。当前故障的关键是:打开 asset 的动作把用户带进了会伪造临时正文的 shell,导致页面主编辑体验看起来像 index.md 被替换成默认 mindmap。
6. 建议修复方向
阶段一:立即止血
- 取消文件树 mindmap asset 点击直接
window.location.assign('/mindmap/{doc}/{asset}')的主路径行为。 - 点击
index.md必须始终打开真实/documents/{documentId}?treeView=filetree,并读取真实 Page Aggregate body。 - mindmap asset 点击只能发出明确的 asset-open intent,不应改写当前页面正文、不应伪造
index.md内容、不应让主编辑区误认为当前正文就是 standalone bootstrap。 - 保留
/mindmap/{doc}/{asset}作为显式独立页面入口时,应只用于新窗口、新 tab、调试入口或明确的 asset editor,不作为普通文件树主点击默认行为。
阶段二:主编辑区 asset tab
建议把文件树里的 mindmap asset 打开为主编辑区内的 asset tab / preview,而不是替换 index.md:
- 标签形态类似
index.md | mindmap.json。 index.mdtab 只显示真实页面正文。mindmap.json或 mindmap asset tab 使用{ documentId, mindmapId }加载 mindmap projection。- asset tab 保存只写 mindmap command / projection 对应资源,不创建第二份页面正文。
- 关闭 asset tab 后回到
index.md,正文内容应保持不变。
阶段三:Page Aggregate 与 block-asset 单一真源
长期应把 mindmap asset 与页面正文 block 关系收口到 Page Aggregate / kernel projection:
- 页面正文中的 mindmap block attrs 持有稳定
mindmapId。 - 文件树 mindmap asset row 来自同一份 page aggregate/resource projection,而不是另起一套对象真相。
- mindmap asset 的删除、恢复、移动、重命名应同步维护 page body block 与 resource projection 的关系。
- standalone shell 如果继续存在,也必须声明自己是 asset editor,不再构造会被误认为
index.md的页面正文 bootstrap。
7. 建议 smoke 验证
修复完成后至少补一条文件树 mindmap 回归 smoke:
- 登录真实测试账号。
- 新建测试页面,插入或生成一个 mindmap block,记录
documentId与mindmapId。 - 从文件树点击该页面下的 mindmap asset。
- 断言主编辑区没有导航到会污染
index.md的 standalone bootstrap;如果打开 asset tab,则 tab 标识与index.md分离。 - 在 mindmap 中输入一段较长中文内容并保存。
- 切换到其它页面,再从文件树点击原页面
index.md。 - 断言
index.md仍显示真实页面正文,且页面内 mindmap block 仍引用同一个mindmapId。 - 再打开 mindmap asset,断言刚才输入的长中文内容仍存在。
需要保留一条负向断言:
- 普通文件树主点击 mindmap asset 不应触发
window.location.assign('/mindmap/{doc}/{asset}')并替换当前文档页正文。
8. 修复证据
本问题已按 4-24 与 5-12 收口:
rust/crates/core-protocol/src/kernel.rs增加KernelObjectIdentity/KernelBlockAssetRelation。rust/crates/bridge-runtime/src/lib.rs的 file tree projection 为index.md、mindmap、OnlyOffice、代码附件、普通附件输出不同resourceMeta.objectIdentity。rust/crates/mnote-web/src/tree_shell/filetree_renderer.rs、rust/crates/mnote-web/src/routes/tree.rs、rust/crates/mnote-web/src/ssr/pages/layout.rs将objectIdentity下发到文件树 DOM 与tree.asset.openintent。/mindmap/{documentId}/{mindmapId}由rust/crates/mnote-web/src/ssr/pages/mindmap.rs明确标记为data-mnote-object-editor="mindmap"与data-mnote-object-identity="resource:mindmap:{documentId}:{mindmapId}"。rust/crates/mnote-web/src/routes/mindmap_shell.rs的 standalone bootstrap 使用__mindmap_object__:{documentId}:{mindmapId},不复用真实页面正文草稿身份。
验证命令:
cd /mnt/Data1T/mnote/rust && cargo test -p core-protocol --test resource_tree_contract -- --nocapture
cd /mnt/Data1T/mnote/rust && cargo test -p bridge-runtime file_tree_projection -- --nocapture
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web file_tree_projection -- --nocapture
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web mindmap -- --nocapture
cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web documents_save_route_executes_page_body_save_command -- --nocapture
cd /mnt/Data1T/mnote/rust/spikes/leptos-tiptap-spike && cargo test standalone_mindmap_object_uses_isolated_draft_identity -- --nocapture
node scripts/task112-tree-rust-family-regression-smoke.js
node scripts/task169-mindmap-realtime-smoke.js
task169 已覆盖:文件树 mindmap asset 打开、长中文编辑、保存、切页、从文件树回 index.md、再次打开 mindmap,且未触发 page.body.save 污染链。
9. 流转条件
当前状态:done
只有在以下条件都满足后,本文才能移动到 bugs/05-editor-mainline/done/:
- 文件树 mindmap asset 普通点击不再污染
index.md主编辑区。 index.md与页面内 mindmap block 的关系有明确单一真源,至少不再出现切页后只剩默认导图的现象。/mindmap/{doc}/{asset}的产品定位被明确为独立页、新 tab、debug 或 asset editor,不再被文件树主路径误用。- smoke 覆盖长中文 mindmap 编辑、保存、切页、回到
index.md、再次打开 asset 的完整链路。 - 浏览器复测确认 mindmap 编辑可用性优先,不因实时刷新或路由切换导致闪烁、跑位或内容错乱。