Files
mnote/design/old/04-tree-domain/done/4-11-tree-rust-family-final-renderer-and-host-thinning-checklist-v1.md
T
Agent Board b798f628ee chore: land tree view-state, vault, Pi module split, and repo hygiene
Persist PageTree expand state via control-plane view-state and align
chevron/DOM with restored expansion; keep Sidex-style shallow page-tree
scan and drop the unused recursive scanner that only added cargo noise.

Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi
into a module package, and retire Hermes/ACP/OpenHub recycle + root
harness evidence from the index while gitignoring recycle and local
diag dumps.

Archive superseded design/bugs docs under old/, point architecture at
ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor
regressions so the working tree can stay clean.
2026-07-21 05:13:05 +08:00

27 KiB
Raw Blame History

[recycle] 4-11 [done] 树域 Rust 家族 final renderer 与宿主收薄清单 v1

更新时间:2026-04-26

前置文档:

  • /mnt/Data1T/mnote/design/old/04-tree-domain/process/4-10-tree-rust-family-cutover-checklist-v1.md
  • /mnt/Data1T/mnote/design/old/04-tree-domain/process/4-9-tree-rust-family-cutover-remaining-architecture-and-capability-preservation-v1.md
  • /mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md

口径覆盖(2026-04-28):此前 rust_runtime_artifact_host、Rust/WASM reducer runtime、Rust initial DOM 与 task112/task113 smoke 通过,只能证明 reducer/runtime 阶段完成,不能证明 final Rust DOM renderer 完成。真正 final renderer 的硬门禁以 /mnt/Data1T/mnote/design/04-tree-domain/done/4-18-tree-final-dom-shell-cutover-hard-gate-v1.md 为准:默认真实流量必须不再依赖 TreeShellIframeHostiframe_srcdoc DOM shell。

收口更新(2026-04-28):task-010task-013 已完成上述 final DOM shell 硬门禁。rust_family 默认真实流量已切到 rust_wasm_dom_shell_host + dom_wasm bridge。

最终清理更新(2026-05-16):TreeShellIframeHost 与对应测试已移动到 recycle/NEXT_PUBLIC_TREE_SHELL_LEGACY_IFRAME_HOST 入口已删除;active source 不再保留 iframe/srcDoc legacy/debug host。

1. 当前已收口基线

  • 3000 仍是唯一浏览器公开入口。
  • page tree / file tree / picker 默认主路径已进入 rust_family 3000 rust_wasm_dom_shell_host
  • 3104 tree shell proxy 已退到显式 debug/internal 边界;默认主站 iframe 不再请求 /api/tree/shell -> mnote-web:3104,避免 desktop:hot 下页面树/文件树显示 {"error":"fetch failed"}
  • file_tree 主路径输入已收口到 kernel file_tree items
  • buildVisibleRows 不再从 pageRows + assets fallback 重建文件树对象语义。
  • streamDelta 已可写入 command_logsdomain_events
  • Rust SSE 与 3000 同源 SSE 都能从单条新 domain_event.payload.streamDelta 直接产出 delta
  • Rust bridge-runtime 已具备 tree.subtree.move 的可测试 canonical move order plan。
  • TS transport 已把 Rust normalizedMove 透传到 Convex documents.move 的可选校验边界。
  • Convex documents.move 在收到 normalizedMove 时会先确认当前排序 patch plan 与 Rust plan 一致,再执行既有兼容写入。
  • Rust SSE 与 3000 同源 SSE 对同一 command_id 的 command log + domain event 双写做 delta 去重:delta 一致时发一次 delta,不一致继续 resync
  • tree.subtree.move 已从 replace_documents 过渡 delta 推进到 move_document 细粒度 delta
    • Rust bridge-runtime 已输出 streamDeltaHint(kind=move_document)domainEventHint(tree.subtree.moved)
    • 3000 /api/tree/commands 按 Rust plan hint + mutation result 物化并写入 move_document
    • 3000 SSE 与 Rust SSE 均保留 documentId / parentId / sortOrder / updatedAt
    • 前端 tree-delta reducer 可用该 delta 重建 sidebar_tree / page_tree / file_tree
  • tree.node.restore / tree.subtree.copy 已从 replace_documents 过渡 delta 推进到细粒度 upsert
    • restore -> upsert_document
    • copy -> upsert_documents
    • 前端 tree-delta reducer 可用 upsert delta 重建 sidebar_tree / page_tree / file_tree
  • Rust bridge-runtime 已输出正式 tree domain event plan
    • tree.node.created / renamed / archived / restored / purged / embedded
    • tree.subtree.moved / copied
    • 每条正式 tree command plan 都带 domainEventPlan(schema=mnote.tree.domain_event, schemaVersion=1, eventType, streamDeltaHint)
    • recordBridgeCommandArtifacts 会优先使用 Rust plan 透传的 event type / materialized streamDelta,而不是 ${command}.requested
  • file_tree 搜索过滤已接入 Rust projection query 主链:
    • KernelProjectionFilter.query 已进入协议
    • KernelProjectionFilter.maxResults 已进入协议
    • Rust kernel.project_view(file_tree) 已能输出命中项与必要祖先
    • Rust 搜索 projection 已按“直接命中项限流,必要祖先不计入上限”执行 maxResults
    • mnote-web /api/tree/projections/file?...&query= 与 3000 同源 /api/tree/projections/file route 已覆盖
    • mnote-web 与 3000 同源 route/client 已透传 maxResults
    • Sidebar 搜索态只消费 Rust 搜索 projection items,旧宿主裁剪 helper 已移除
  • tree realtime 主链已补强:
    • command log 与 domain event 双写时,即使上一帧 cursor 来自另一条流,也会按时间排除旧 artifact 后再做同 command_id delta 去重
    • 未识别 domain event payload 继续保守 resync
    • TS artifact 写入边界已固定 mnote.tree.domain_event payload schema v1,并保留历史 snake_case 字段兼容 SSE
  • resource command 主链已补强:
    • tree.resource.copy / tree.resource.move 已由 Rust bridge-runtime 生成 resourceTransferPlan
    • tree.resource.upload 已由 Rust bridge-runtime 生成 resourceUploadPlan
    • Convex mediaAssets.batchCopy / batchMove / createWithStorage 已按 Rust plan 做可选一致性校验
    • tree.resource.copied / moved / uploaded 已可生成 asset_result -> upsert_assets delta / domain event plan
    • 3000 media batch/upload route 已改为调用 Rust artifact writer,按 Rust artifact plan 持久化 command_logs / domain_events
    • Sidebar 对 copy / move / rename / delete / restore / upload 的资源请求已抽成 file-tree/resource-command-client
  • file tree 内部 drop 已新增 Rust command preflight
    • tree.filetree.drop.preflight 由 Rust bridge-runtime 归一化 target、row 去重、doc/asset 分类、mindmap subPath、copy/move action
    • Rust preflight 会拒绝页面移动到自身/后代
    • preflight plan 已输出 documentTransferPlanresourceTransferPlanSidebar 内部 drop 主路径改为先消费 Rust plan 再触发既有 transport
    • 宿主仍负责实际命令触发、乐观 UI、副作用通知和错误提示
  • file tree 删除目标已新增 Rust command preflight
    • tree.filetree.delete.preflight 由 Rust bridge-runtime 归一化 row 去重、父页面覆盖过滤、doc/asset 删除目标
    • Rust delete plan 会在“选中父页面”时过滤其子页面附件,避免宿主重复构造 asset 删除列表
    • Sidebar 删除确认与执行主路径改为先消费 Rust delete plan,再触发既有 document/media transport
  • file tree 粘贴目标与复制分类已新增 Rust command preflight
    • tree.filetree.paste.preflight 由 Rust bridge-runtime 归一化剪贴板 row、目标页面、focused row、doc/index 复制递归语义、真实 asset 过滤和 mindmap targetSubPath
    • 3000 同源 /api/tree/filetree/paste-preflight route 与 client 已覆盖
    • Sidebarrust_family 粘贴主路径先消费 Rust paste plan,再触发既有 copyTreeCommand / copyFileTreeResourceAssets
  • file tree 外部上传目标已新增 Rust command preflight
    • tree.filetree.upload-target.preflight 由 Rust bridge-runtime 归一化 drop target、focused row、active doc、目标 workspace 与 mindmap targetSubPath
    • 3000 同源 /api/tree/filetree/upload-target-preflight route 与 client 已覆盖
    • Sidebar 外部文件 drop 主路径先消费 Rust upload target plan,再执行既有文件字节读取与 upload transport
  • Rust tree shell 已新增可测试 renderer/state family 基础合同:
    • renderer_input 覆盖 page / filetree / picker 的 projection items、expanded ids、focused id、selected row ids、active picker item、excluded ids、command dispatcher
    • mnote-web tree shell HTML 已嵌入 Rust 构建的 rendererInput JSON contract,供 compat host 与后续 final renderer 共用;compat shell 初始 expanded / selection / picker active / exclude 已优先读取该合同
    • 3000 默认 TreeShellRustDomShellHost 已对齐同一 projection modelpage / filetree / picker 的 projection items 进入 DOM host modelTreeShellIframeHost 的 appState JSON 只保留在 legacy/debug host。
    • rendererInput 已继续暴露三类 reducer contractrust_page_focus_keyboard_reducer_v1rust_filetree_selection_reducer_v1rust_picker_state_reducer_v1
    • mnote-web /tree debug shell 与 3000 legacy inline compat host 均已消费同名 reducer contract;当前默认 DOM host 已切到 TreeShellRustDomShellHost,并通过 WASM artifact 或同源 Rust reduce seam 执行 runtime。
    • 前端 TreeShellHost 已暴露 data-tree-renderer-contract=rust_renderer_input_v1,主路径 data-tree-host-implementation=rust_wasm_dom_shell_hostmnote_web_iframe_proxyrust_inline_compat_hostrust_runtime_artifact_host 不再代表默认主执行面
    • filetree_selection 覆盖单选、多选、Shift 范围选、右键选中、清空、visible rows 归一化、drag row ids
    • picker_state 覆盖高亮归一化、上下/Home/End、排除项、Enter pick
    • focus_state 覆盖 focused id 归一化与 next/previous/home/end 行走
    • expansion_state 覆盖默认展开、toggle、活动节点祖先展开
    • keyboard_state 覆盖导航、打开、展开/折叠、上下文菜单 intent
    • drag_drop_state 覆盖拖拽 payload 去重归一化与 copy/move effect
    • action_registry 覆盖 page/filetree/picker 的可用动作集合
    • page_renderer 已输出 data-rust-page-renderer=initial_v1 的 page tree 首屏嵌套 HTML,并由 compat runtime 优先 hydrate 该 Rust DOM;后续状态变化仍保留 JS 重绘路径
    • filetree_renderer 已输出 data-rust-filetree-renderer=initial_v1 的 file tree 首屏嵌套 HTML;历史 3000 inline srcDoc 曾优先 hydrate 该 DOM,当前默认主路径已由 TreeShellRustDomShellHost 承载,legacy iframe 与 mnote-web /tree 仅保留 debug/internal 验证边界。
    • picker_renderer 已输出 data-rust-picker-renderer=initial_v1 的 picker 首屏 HTML;历史 3000 inline srcDoc 曾优先 hydrate root/item DOM,当前默认主路径已由 TreeShellRustDomShellHost 承载,legacy iframe 与 mnote-web /tree 仅保留 debug/internal 验证边界。
  • Rust artifact 写路径已开始落地:
    • bridge-runtime 已新增 RuntimeCommandArtifactPlan,可从 Rust command plan + mutation result 物化 commandLogmnote.tree.domain_event payload
    • mnote-web /api/tree/commands 已在 Rust transport 内持久化 bridgeLogs.recordCommandLog / recordDomainEvent
    • artifact 写入失败不会回滚已成功 mutation,响应会暴露 artifactError 供观测
    • 3000 /api/tree/commands/api/media/batch/api/media/upload、文档类 page/save/lifecycle/metadata/page-write/documents-block Rust transport adapter 已改为调用 Rust artifact writer
    • documents.duplicate 已补正式 tree.node.duplicated domain event plan3000 duplicate 成功链不再回退 TS artifact helper
    • 当前显式 adapter 层已不再直接调用 TS recordBridgeCommandArtifacts(...)
  • file tree selection 的宿主职责已继续收薄:
    • rust_familySidebar 不再把 legacy React file tree selection reducer 作为选择真相
    • Sidebar 只从 tree.filetree.selection.changed 事件物化 renderer selection snapshot,删除 / 复制 / 粘贴 / 上传 / 内部 drop 只读消费该 snapshot
    • SidebarTreeSurface 不再向 Rust file tree host 传 selectedRowIds 控制 prop,避免宿主反向控制 renderer selection
    • compat runtime 在 file tree 重绘与可见行归一化后会继续回发 selection snapshot,避免宿主业务消费旧镜像
    • compat runtime 的 Shift 范围选择与右键选中语义已对齐 Rust filetree_selection 合同:Shift 默认覆盖旧选择,Ctrl/Cmd+Shift 才叠加;右键已选中行保留多选集合

2. 已完成的 final DOM shell 硬边界与仍未完成项

  • 2026-04-28 final DOM shell 硬门禁已完成:TreeShellIframeHostiframe_srcdoc browser bridge 不再是默认 page tree / file tree / picker DOM shell。
  • page tree / file tree / picker 3000 默认主路径已标识为 rust_wasm_dom_shell_host,默认浏览器 bridge 为 data-tree-browser-bridge="dom_wasm"
  • TreeShellIframeHost 已从 active source 移到 recycle/;旧 LOCAL_TREE_SHELL_TEMPLATEbuildInline*Html 不再参与 active 路径。
  • 默认 DOM host 已通过 TreeShellRuntimeRequest/Result 消费 WASM artifact 或同源 Rust HTTP seam 返回的 state、hostEvents、commandEvents;本地 JS fallback reducer 不再参与默认真实流量。
  • 仍未完成的是非 DOM shell 范围:tree.subtree.movenormalizedMove compat fallback 删除、document.snapshot.saved 独立事件、tree.node.embed Page Aggregate/Rust artifact 深层收口等历史条目的后续核验;legacy iframe host 清理已完成。
  • 宿主仍承担文件字节读取、外部上传 transport、菜单状态、实际命令调度、乐观 UI 和副作用通知;资源 upload/copy/move、内部 drop preflight、粘贴 preflight、外部上传目标 preflight 的目标与 metadata plan 已进入 Rust command contract。
  • tree.subtree.move 的 canonical sort plan 已在 Rust 产出并进入 Convex 可选校验,但实际排序写入仍由 Convex documents.move 执行。
  • file_tree 搜索过滤主链已改为 Rust projection querymaxResults / index.md / 附件 / 导图子附件 / book/pdf 扩展 fixture 已补齐,后续仅保留更丰富搜索语义 hardening。
  • replace_documents 已退为 restore/copy 的 fallback;主路径 restore/copy 已是 upsert_document(s)
  • Rust command 已生成 tree/resource delta / domain event planmnote-web /api/tree/commands、3000 tree/media 主写入口与文档类 Rust transport adapter 已可由 Rust artifact writer 落 command_logs / domain_eventsblock/save 复合命令已形成 page.body.savedblock.patchedblock.movedblock.embedded formal domain-event contract。
  • block/save 复合命令已并入正式 Rust artifact 主链;OnlyOffice/media writeback 已切到 Rust artifact writer。document.snapshot.saved 是否作为独立事件继续留在 4-16,不阻塞本文件 final renderer / host thinning 收口。

3. Phase Ffinal Rust renderer 接入

目标

page tree / file tree / pickerTreeShellIframeHost 内联 DOM compat shell,迁到正式 Rust family renderer。

状态:默认主路径已完成迁移,legacy iframe host 已移入 recycle/,不再作为显式排障开关保留。

checklist

  • 固定 Rust renderer 输入合同:
    • projection items
    • expanded ids
    • focused id
    • selected row ids
    • active picker item
    • command dispatcher
    • 当前已作为 rendererInput 嵌入 mnote-web tree shell HTMLruntime DOM shell 已优先读该合同初始化局部状态,但尚未完全改为只消费该合同。
    • 历史 3000 inline host 已把 rendererInputitems 注入同一个 appState;当前默认 DOM host 直接消费 projection model,不再通过 __MNOTE_TREE_SHELL_OVERRIDE__ 主路径注入第二份 items。
    • 默认 DOM shell 已固定 family=rust_family / version=1 / executionStrategy=dom_wasm,并优先使用 3000 同源 tree-shell-runtime artifactactive source 不再保留 browserBridge=iframe_srcdoc host。
    • runtime artifact manifest 已新增 runtimeApi,显式暴露 TreeShellRuntimeRequest / TreeShellRuntimeResult、state snapshot、DOM patch、host event、command event kind。
    • runtime artifact manifest 已继续暴露 reduceEndpoint=/api/tree/runtime/reduce3000 同源 thin proxy 与 mnote-web endpoint 保留为 fallback/debug。
    • 正式 Rust/WASM reducer runtime 已落地:tree-shell-runtime-wasm 导出 reduceTreeShellRuntime3000 主路径默认优先加载 mnote-tree-shell-runtime.jsmnote-tree-shell-runtime_bg.wasm 执行 reduce。
  • 拆出 renderer 内部模块:
    • row model 雏形(page/filetree/picker renderer test id contract
    • page initial DOM renderer(首屏 page tree Rust HTML + hydrate contract
    • filetree initial DOM renderer(首屏 file tree Rust HTML contract
    • picker initial DOM renderer(首屏 picker Rust HTML contract
    • expansion model(默认展开 / toggle / 祖先展开 state family
    • focus modelfocused id normalize / next / previous / home / end
    • selection modelfiletree selection state family
    • picker state model(高亮 / Enter / exclude
    • keyboard model(导航 / 打开 / expand-collapse / context menu intent
    • drag/drop modelpayload normalize / copy-move effect
    • action registrypage / filetree / picker action set
    • runtime facadeTreeShellRuntimeRequest / TreeShellRuntimeResult 可序列化 API,输出统一 DOM patch / host event / command event
  • page tree 先切 final renderer。
    • 当前状态:默认 page tree 由 TreeShellRustDomShellHost 渲染 DOMfocus / keyboard / expand / collapse / toggle / open / context menu / move command dispatch 均通过 TreeShellRuntimeRequest/Result 返回结果驱动。
  • picker 以轻量模式复用同一 renderer state family。
    • 当前状态:默认 picker 由 TreeShellRustDomShellHost 渲染 DOMkeyboard command、hover focus、click pick 均通过 runtime state 与 hostEvents 驱动,测试已禁止默认 iframe postMessage 成功路径。
  • file tree 后切 final renderer,并保留 doc / index / asset-folder / asset 能力。
    • 当前状态:默认 file tree 由 TreeShellRustDomShellHost 渲染 DOMselection、context menu、open、internal/external drop 与 drop target 通过 runtime result/hostEvents 驱动,并保留 doc/index/asset-folder/asset row 口径。
  • compat host 退为 debug/internal fallback(本批可验证范围)。
    • 3000 默认主路径不再请求 /api/tree/shell -> mnote-web:3104,也不再回退旧 React rendererhost implementation 已切到 rust_wasm_dom_shell_hostmnote-web /tree 仅保留显式 debug/internal 验证边界,TreeShellIframeHost 已进入 recycle/

验收

  • 默认真实流量不再以 rust_inline_compat_hostrust_runtime_artifact_hostTreeShellIframeHost 作为主路径标识;page / picker / filetree 默认路径已不再依赖 iframe_srcdoc 内联 DOM renderer。
  • data-tree-host-implementation 不再以 mnote_web_iframe_proxy 代表主执行面。
  • page tree / file tree / picker smoke 仍覆盖打开、键盘、选择、拖放、菜单。

4. Phase G:宿主状态机收薄

目标

宿主只保留挂载、认证、文件读取、transport bridge,不再解释树域交互合法性。

checklist

  • 上传执行从 sidebar 宿主抽成正式 resource command。
    • tree.resource.upload 已进入 Rust plan / domain event hint / asset_result delta
    • 浏览器文件字节读取与 Convex upload URL 仍由 3000 upload route 执行
  • 内部 file tree drop payload 归一化进入 Rust command preflight。
    • tree.filetree.drop.preflight 已接 3000 同源 route /api/tree/filetree/drop-preflight
    • 前端 file-tree/shell 只负责从 projection row / parent snapshot 构造 preflight payload
    • Rust plan 输出 target、mindmap subPath、doc/asset 分类、top-level doc、source asset documents、documentTransferPlanresourceTransferPlan
  • copy/move 区分与非法投放校验进入 Rust command/projection contract。
    • tree.filetree.drop.preflight 已按 copy 输出文档/资源 transfer plan
    • 非 copy 的页面移动已在 Rust preflight 拒绝自身/后代投放
    • 更完整的跨工作空间/混合对象权限校验仍随正式 Rust 写路径继续下沉
  • file tree 删除目标归一化进入 Rust command contract。
    • tree.filetree.delete.preflight 已接 3000 同源 route /api/tree/filetree/delete-preflight
    • Sidebar 删除链已先消费 Rust delete plan,再执行既有 deleteDocumentCommand / deleteFileTreeResourceAssets
    • legacy computeFileTreeShellDeleteTargets 已退出生产代码,只保留 Rust preflight payload builder
  • file tree 粘贴目标推导与复制对象分类进入 Rust command contract。
    • tree.filetree.paste.preflight 已接 3000 同源 route /api/tree/filetree/paste-preflight
    • Rust paste plan 已输出 docItemsresourceTransferPlan,覆盖 doc -> recursive trueindex -> recursive false、真实 asset 过滤和 mindmap targetSubPath
    • Sidebarrust_family 粘贴链已不再本地推导 docItemsMap / copyableAssetIds,只消费 Rust paste plan 后触发既有 transport
  • file tree 外部上传目标推导进入 Rust command contract。
    • tree.filetree.upload-target.preflight 已接 3000 同源 route /api/tree/filetree/upload-target-preflight
    • Rust upload target plan 已输出 workspaceId / targetDocumentId / targetMindmapId / targetSubPath
    • Sidebar 的外部文件 drop 链已不再本地推导 target row / focused row / workspace fallback,只消费 Rust upload target plan 后执行既有 upload transport
  • 多选、范围选、右键选中状态进入 renderer state family。
    • Rust filetree_selection 已有纯状态测试;mnote-web /tree 与 3000 legacy inline compat runtime 均已通过 rust_filetree_selection_reducer_v1 合同入口执行选择、右键、可见行归一化与 drag rows 解析;当前默认 DOM host 已通过 TreeShellRuntimeRequest/Result 消费 Rust/WASM runtime。
  • picker 高亮、Enter 选中、排除项规则进入 renderer state family。
    • Rust picker_state 已有纯状态测试;mnote-web /tree 与 3000 legacy inline compat runtime 已通过 rust_picker_state_reducer_v1 合同入口执行 next/previous/home/end/pick/focus;当前默认 DOM host 已通过 TreeShellRuntimeRequest/Result 消费 Rust/WASM runtime。
  • 宿主不再持有 file tree 选择真相,只订阅 renderer state event。
    • Sidebar 已拆分 legacy selection 与 renderer selection snapshotrust_family 下只有 handleFileTreeShellSelectionChange 写入 renderer snapshot。
    • SidebarTreeSurface 已移除 selectedRowIds 控制输入,file tree 选择只能由 renderer event 回报给宿主业务。
    • 仍未完成:compat runtime 内部选择算法虽已统一为 rust_filetree_selection_reducer_v1 合同入口,但尚未替换为 Rust runtime/wasm 直接执行,继续归入 Phase F final renderer / runtime 收口。

验收

  • sidebar 宿主不再包含主要 file tree selection truth 分支;drop legality 仍通过 Rust preflight + 宿主 transport 过渡执行。
  • 上传和资源移动失败能返回稳定 command error,不依赖前端临时判断。
  • renderer state 可独立测试,不需要挂载整个 sidebar。

5. Phase HRust 搜索 projection

目标

file_tree 搜索过滤不再由宿主裁剪 kernel file_tree items,而是由 Rust 输出搜索 projection。

checklist

  • 定义 file_tree.search 基础输入:
    • query
    • root node
    • include ancestors
    • include assets
  • 补齐 file_tree.search 扩展输入:
    • index.md 显式作为可搜索资源;仅自身命中时进入结果,祖先仅用于维持路径
    • maxResults 限制直接命中项,必要祖先不计入上限
  • 定义搜索结果展开策略:
    • 命中页祖先展开
    • 命中 asset-folder 展开
    • 空结果稳定空态
  • Rust projection fixture 覆盖:
    • mindmap folder
    • table
    • 命中项必要祖先
  • 补齐搜索 fixture 扩展覆盖:
    • index.md
    • 附件
    • 导图子附件
    • book/pdf
  • 前端只消费搜索 projection items,不再计算 visible document ids。

验收

  • 搜索态、空态、正常态都由同一 Rust projection contract 驱动。
  • 前端不再持有搜索过滤的对象语义。
  • Phase H 当前验收已满足;后续 richer search semantics 作为 hardening,不再阻塞主链。

6. Phase Imove 排序执行下沉

目标

tree.subtree.move 的排序执行从 Convex compat mutation 迁到 Rust kernel command 主链。

checklist

  • Rust 已有 canonical move order plan 纯函数。
  • Rust command plan 已可输出 normalizedMove
  • Convex documents.move 增加可选校验:若传入 Rust normalizedMove,执行前确认 patch plan 一致。
  • TS transport 对 documents:move 透传 normalizedMove,避免 Rust plan 停在不可观测状态。
  • Rust command plan 已产出正式 tree.subtree.moved domain event hint。
  • mnote-web /api/tree/commands Rust 写路径已可直接持久化正式 tree.subtree.moved domain event。
  • 前端/stream 不再由 Next route 写 replace_documents 作为 move 主 delta。
  • 细粒度 move delta reducer 同时更新 sidebar_tree / page_tree / file_tree
  • move_document 不再由 Next route 按 action 手写;当前由 Rust streamDeltaHint + mutation result 物化。
  • mnote-web /api/tree/commandsmove_document artifact 已由 Rust transport 直接生成/落库。
  • 3000 Next 主写入口已切到 Rust artifact writer。

验收

  • sort order clamp、同父移动、跨父移动、重复 sort_order、null sort_order、created_at tie-break 均由 Rust 测试锁定。
  • Convex 只作为存储执行层,不再持有唯一排序规则。

7. Phase J:正式 delta 主链

目标

树域 realtime 从 replace_documents 过渡 delta,推进到 Rust domain event 驱动的细粒度 delta。

checklist

  • domain event 可携带并被 SSE 解释 streamDelta
  • command log 与 domain event 同一 command_idstreamDelta 一致时,SSE 发一次 delta 而不是退回 resync
  • 定义正式 domain event type hint
    • tree.node.created
    • tree.node.renamed
    • tree.node.archived
    • tree.node.restored
    • tree.node.purged
    • tree.node.duplicated
    • tree.subtree.moved
    • tree.subtree.copied
    • tree.resource.copied
    • tree.resource.moved
    • tree.resource.uploaded
  • 定义正式 domain event payload schemaTS artifact 写入边界与 Rust artifact writer 均固定 mnote.tree.domain_event v1
  • Rust 侧由 command plan 生成 delta / event hintNext route 不再按 action 拼主 delta / event type。
  • mnote-web /api/tree/commands Rust 写路径已由 command result 直接生成并持久化 domain event。
  • 显式 compat adapter 写入口已迁出 TS artifact transport。
  • block/save-snapshot 复合命令已补齐正式 Rust artifact / domain-event contract。
    • 当前完成口径:page.body.saved payload 已携带 snapshot 摘要,block.patched / block.moved / block.embedded 已有 formal domain-event contract。
    • document.snapshot.saved 是否拆成独立事件继续留在 4-16,不阻塞本阶段收口。
  • 前端 reducer 支持细粒度 move。
  • 前端 reducer 支持细粒度 restore/copy
    • upsert_document
    • upsert_documents
  • 前端 reducer 支持资源 upsert delta
    • upsert_assets
  • 未识别事件继续保守 resync

验收

  • 新树命令默认有 domain event delta。
  • replace_documents 仅作为 fallback,不再是 move / restore / copy 主路径。

8. 不做事项

  • 不为了“看起来 Rust 化”把 React/DOM compat shell 原样翻译成另一层大壳。
  • 不在 sidebar 继续新增树对象真相。
  • 不把 3104 恢复成默认浏览器入口。
  • 不在 Next route 继续扩写长期树命令语义。