Files
mnote/design/01-tree-first-graph-kernel/process/1-5-next-phase-sequential-execution-checklist-v1.md
T
lix-2026 42fb58310c chore: retire remaining convex infrastructure
- move self-hosted Convex infra and root placeholder into recycle

- update architecture docs to remove active infra/convex deployment guidance

- extend local-first Convex guard to block retired infra regressions
2026-05-22 19:31:20 +08:00

30 KiB
Raw Blame History

1-5 [process] 下一阶段顺序执行 checklist v1

创建时间:2026-05-19

当前状态:PROCESS

上位依据:

  • /mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-4-next-phase-execution-roadmap-v1.md
  • /mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-3-current-priority-execution-checklist-v1.md
  • /mnt/Data1T/mnote/design/05-editor-mainline/reference/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md

目标:给出一份可以顺序执行、每一步都有完成验收、且标明参考源码位置的下一阶段执行清单。


0. 执行原则

  • 每个阶段必须先补或确认测试,再改实现。
  • 每个阶段只能收口当前主链,不新增通用 IDE 产品面。
  • 新增长期命令必须优先走 tree.* / tree.resource.* / page.*,不能继续扩 documents.*
  • 涉及本地文件写入时,必须携带 workspace identity、allowed roots、expected file version。
  • 涉及 UI / live stream 时,必须补 browser smoke 或复用既有 smoke。
  • 每完成一个阶段,必须把验证命令和 smoke 证据写回本文件或 1-3

1. Phase A0:建立执行基线

目标:

确认当前 P0-P3 既有能力仍然稳定,避免在架构收口前带着红灯推进。

1.1 基线验证

  • 运行 Rust 格式检查。

    • 命令:cargo fmt --check --all --manifest-path rust/Cargo.toml
    • 完成验收:命令通过。
  • 运行 local-first 权限与 workspace 基线测试。

    • 命令:cargo test -p mnote-web local_folder -- --nocapture
    • 命令:cargo test -p mnote-web local_access_policy -- --nocapture
    • 命令:cargo test -p mnote-web hermes_client_local_acp -- --nocapture
    • 完成验收:三组测试通过。
  • 运行 Page Aggregate / tree command 基线测试。

    • 命令:cargo test -p mnote-web page_aggregate -- --nocapture
    • 命令:cargo test -p mnote-web tree_command -- --nocapture
    • 完成验收:两组测试通过。
  • 运行 local-first guard。

    • 命令:npm run check:local-first-convex-guard
    • 完成验收:命令通过,新增路径没有把 Convex 恢复成默认正文主存储。

1.2 基线 smoke

  • 冲突 UI smoke。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js
    • 完成验收:tiptap 与外部/agent 写入冲突仍能显示、合并、保存。
  • 本地搜索索引 smoke。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task452-local-search-index-browser-smoke.js
    • 完成验收:新建、重命名、搜索、反链、标签仍稳定。
  • agent changed files smoke。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task453-local-folder-page-ai-changed-files-smoke.js
    • 完成验收:AI 写入后 UI 能显示 agent.changed_files

2. Phase A1:统一 WorkspacePath / ProjectPath / ObjectIdentity

目标:

用一个 Rust 侧稳定身份表达“哪个 workspace root 下的哪个对象 / 文件 / 资源”。

2.1 当前代码锚点

  • MNote
    • rust/crates/core-protocol/src/kernel.rs
      • KernelObjectIdentity
      • PageBodyWriteRequest
    • rust/crates/core-protocol/src/lib.rs
    • rust/crates/mnote-web/src/routes/local_folder_source.rs
    • rust/crates/mnote-web/src/ssr/pages/layout.rs
      • fileObjectIdentity
      • readFileTreeObjectIdentity
    • rust/crates/mnote-web/src/routes/tree.rs

2.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/project/src/project.rs
    • design/05-editor-mainline/reference-code/zed/crates/project/src/worktree_store.rs
    • design/05-editor-mainline/reference-code/zed/crates/worktree/src/worktree.rs
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/path_util.rs
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/multi_root.rs
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/workspace.rs

2.3 顺序任务

  • 盘点当前所有 path key / object key。

    • 搜索命令:rg -n "ObjectIdentity|objectIdentity|rootUri|relativePath|fileVersion|documentId" rust/crates/mnote-web rust/crates/core-protocol -S
    • 完成验收:列出哪些入口仍只用 documentId、绝对路径或前端拼接 key。
  • core-protocol 中明确 WorkspacePath 或等价结构。

    • 建议字段:workspace_idroot_uriroot_idrelative_pathsource_kindobject_identityresource_kind
    • 完成验收:结构能表达页面 .md、mindmap、office、附件、目录节点。
  • 给 local folder file tree 输出稳定 identity。

    • 重点文件:rust/crates/mnote-web/src/routes/local_folder_source.rs
    • 完成验收:File Tree row、Page Tree row、Resource row 均能携带统一 identity,不再由前端临时猜测。
  • 前端 sidebar/filetree 消费统一 identity。

    • 重点文件:rust/crates/mnote-web/src/ssr/pages/layout.rs
    • 完成验收:fileObjectIdentity / readFileTreeObjectIdentity 不再作为事实源,只作为兼容读取层。

2.4 验收

  • 单测覆盖 identity 序列化与反序列化。

    • 建议命令:cargo test -p core-protocol object_identity -- --nocapture
  • local folder tree 测试覆盖页面 .md 和资源对象 identity。

    • 建议命令:cargo test -p mnote-web local_folder -- --nocapture
  • 浏览器 smoke 覆盖 filetree active reveal 和标题同步。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task438-filetree-title-md-active-reveal-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task440-page-title-filetree-md-sync-smoke.js

完成标准:

  • 本地页面、资源、附件、目录节点都能映射到同一套 workspace identity。
  • UI 不再需要通过文件名或 DOM 属性临时反推对象身份。

3. Phase A2:建立 BufferStore / DocumentBuffer 最小模型

目标:

让 tiptap autosave、AI 文件写入、外部编辑器修改围绕同一份打开态、dirty 状态和文件版本仲裁。

3.1 当前代码锚点

  • rust/crates/core-protocol/src/kernel.rs
    • PageBodyWriteRequest.expected_file_version
  • rust/crates/mnote-web/src/routes/documents.rs
    • /api/page-body/write
    • /api/documents/save compat
  • rust/crates/mnote-web/src/routes/local_folder_source.rs
    • write_local_markdown_page_body
    • save_local_markdown_page
  • rust/crates/mnote-web/src/routes/web_shell.rs
    • conflictDetectionKey
    • fileVersion
  • rust/crates/mnote-web/src/routes/editor.rs

3.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/project/src/buffer_store.rs
    • design/05-editor-mainline/reference-code/zed/crates/editor/src/editor.rs
  • Lapce
    • design/05-editor-mainline/reference-code/lapce/lapce-app/src/doc.rs
  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/platform/files
    • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/services/filesConfiguration

3.3 顺序任务

  • 盘点所有文件写入口。

    • 搜索命令:rg -n "documents.save|page.body.save|page-body/write|write_local_markdown|expectedFileVersion|conflictDetectionKey" rust/crates -S
    • 完成验收:列出 tiptap、Hermes tool、page save、documents compat、外部 watcher 入口。
  • 定义 DocumentBuffer 最小字段。

    • 建议字段:workspace_pathfile_versionbase_content_hashcurrent_content_hashdirty_stateexternal_change_statelast_loaded_atlast_saved_at
    • 完成验收:字段能覆盖 clean、dirty、stale、external modified、deleted 五种状态。
  • /api/page-body/write 成为本地 .md 正文写入主入口。

    • 重点文件:rust/crates/mnote-web/src/routes/documents.rs
    • 完成验收:本地 markdown 写入必须携带 expectedFileVersiondocuments/save 只作为 compat adapter。
  • 把冲突 UI 的 source 数据改为来自 buffer 状态。

    • 重点文件:rust/crates/mnote-web/src/ssr/pages/layout.rs
    • 完成验收:冲突面板能显示 editor base version、disk version、source actor。

3.4 验收

  • stale 写入被拒绝。

    • 命令:cargo test -p mnote-web local_folder_documents_save_rejects_stale_expected_file_version -- --nocapture
  • Page Body 写入测试通过。

    • 命令:cargo test -p mnote-web page_aggregate -- --nocapture
  • 冲突 UI smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js

完成标准:

  • tiptap、AI、外部修改共享同一版本仲裁模型。
  • 外部文件变更不能静默覆盖 dirty buffer。
  • documents/save 不再被新增路径当作长期主入口。

4. Phase A3Page Aggregate 写读主链继续收口

目标:

页面头部、正文、设置、树投影都通过 Page Aggregate 主链回流 UI。

4.1 当前代码锚点

  • rust/crates/core-protocol/src/page_aggregate.rs
  • rust/crates/mnote-web/src/routes/documents.rs
  • rust/crates/mnote-web/src/ssr/pages/document.rs
  • rust/crates/mnote-web/src/ssr/pages/layout.rs
  • rust/crates/bridge-runtime/src/lib.rs
  • rust/crates/storage-convex-bridge/src/mapping.rs

4.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/project/src/project.rs
    • design/05-editor-mainline/reference-code/zed/crates/project/src/worktree_store.rs
  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files

4.3 顺序任务

  • 盘点仍直接拼 meta + content 或读取 documents.content 的 runtime 路径。

    • 搜索命令:rg -n "documents.content|getContent|getMeta|meta \\+ content|page_aggregate|pageAggregate" rust/crates wolai-frontend src -S
    • 完成验收:列出仍存在的 runtime fallback,并标记 compat only 或待删除。
  • 标题、正文、页面设置写入后只触发 Page Aggregate refresh。

    • 重点文件:rust/crates/mnote-web/src/routes/documents.rs
    • 重点文件:rust/crates/mnote-web/src/ssr/pages/layout.rs
    • 完成验收:写入后 UI 更新来源能追溯到 Page Aggregate,而不是局部补偿状态。
  • 明确 documents.* 在 Page Aggregate 中的兼容边界。

    • 重点文件:rust/crates/storage-convex-bridge/src/mapping.rs
    • 完成验收:新增语义不再加到 documents.*,旧命令只作为 adapter。

4.4 验收

  • Page Aggregate Rust 测试通过。

    • 命令:cargo test -p mnote-web page_aggregate -- --nocapture
    • 命令:cargo test -p bridge-runtime page_aggregate -- --nocapture
  • 页面标题、正文、设置 smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task110-page-title-single-truth-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task-page-aggregate-body-sync-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task-page-aggregate-options-sync-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task-page-aggregate-refresh-persistence-smoke.js

完成标准:

  • 文档页不再新增 meta + content 拼装真相。
  • 标题、正文、页面设置刷新后仍一致。
  • Page Aggregate provenance 能清楚区分 local markdown、compat join、kernel projection。

5. Phase A4tree command / tree.resource command 收口

目标:

页面和资源操作统一走 tree.* / tree.resource.*documents.* 只保留兼容。

5.1 当前代码锚点

  • rust/crates/mnote-web/src/routes/tree.rs
  • rust/crates/bridge-runtime/src/lib.rs
  • rust/crates/storage-convex-bridge/src/mapping.rs
  • rust/crates/mnote-cli/src/lib.rs
  • rust/crates/mnote-web/src/transport/convex.rs

5.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/project_panel/src/project_panel.rs
  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/platform/commands
    • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/src-tauri/src/commands/fs.rs
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/file_operations.rs

5.3 顺序任务

  • 盘点仍使用 documents.* 的命令入口。

    • 搜索命令:rg -n "\"documents\\.|documents\\." rust/crates infra src wolai-frontend -S
    • 完成验收:输出保留清单,逐项标记为 compat adaptertest fixturemust cutover
  • 将新增页面操作固定为 tree.node.*

    • 完成验收:新建、重命名、移动、归档、恢复、删除不再新增 documents.* 调用。
  • 将资源操作固定为 tree.resource.*

    • 完成验收:mindmap、office、附件 rename/move/archive/restore/purge 都有正式命令名。
  • mnote-cli 中历史 documents.* 命令降级为 compat。

    • 重点文件:rust/crates/mnote-cli/src/lib.rs
    • 完成验收:CLI 新增命令使用 tree.*tree.resource.*

5.4 验收

  • tree command 单测通过。

    • 命令:cargo test -p mnote-web tree_command -- --nocapture
    • 命令:cargo test -p bridge-runtime tree_command -- --nocapture
  • 文件树操作 smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task179-tree-create-delete-no-reload-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task446-tree-rename-dual-browser-live-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task447-tree-move-order-dual-browser-live-smoke.js

完成标准:

  • 新增长期命令面不再出现 documents.*
  • storage-convex-bridge 只把正式命令映射到 Convex 兼容 mutation。
  • 资源生命周期命令能统一产生 tree stream delta hint。

6. Phase A5tree realtime live cache 收口

目标:

Sidebar、File Tree、Page Tree、Page Subtree 都消费同一套 snapshot / delta / resync live cache。

6.1 当前代码锚点

  • rust/crates/mnote-web/src/routes/sse.rs
  • rust/crates/mnote-web/src/routes/realtime_ws.rs
  • rust/crates/mnote-web/src/ssr/pages/layout.rs
    • tree:snapshot
    • tree:delta
    • tree:resync
    • deltaNeedsProjectionRefresh
  • rust/crates/bridge-runtime/src/lib.rs
    • tree_stream_delta_hint
    • materialize_tree_stream_delta

6.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/worktree/src/worktree.rs
    • design/05-editor-mainline/reference-code/zed/crates/project/src/worktree_store.rs
  • Lapce
    • design/05-editor-mainline/reference-code/lapce/lapce-proxy/src/watcher.rs
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/watcher.rs

6.3 顺序任务

  • 盘点所有 tree/page/filetree 刷新来源。

    • 搜索命令:rg -n "tree:snapshot|tree:delta|tree:resync|EventSource|WebSocket|poll|refetch|preferred snapshot|pageSubtree" rust/crates/mnote-web/src -S
    • 完成验收:标出 WS 主链、SSE fallback、polling/refetch 补偿链。
  • 明确 WS 是主链、SSE 是 fallback。

    • 重点文件:rust/crates/mnote-web/src/ssr/pages/layout.rs
    • 完成验收:SSE 不和 WS 并行长期消费同一事件,只有 WS 不可用时 fallback。
  • delta 能处理时直接 apply,不能处理时 resync。

    • 重点文件:rust/crates/mnote-web/src/ssr/pages/layout.rs
    • 重点文件:rust/crates/bridge-runtime/src/lib.rs
    • 完成验收:deltaNeedsProjectionRefresh 不再成为常态路径。
  • 删除或降级不必要的 polling / refetch 补偿链。

    • 完成验收:页面/文件树操作不靠定时轮询才能稳定。

6.4 验收

  • realtime route 单测通过。

    • 命令:cargo test -p mnote-web tree_realtime -- --nocapture
    • 命令:cargo test -p mnote-web local_folder -- --nocapture
  • 双浏览器 live smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task446-tree-rename-dual-browser-live-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task447-tree-move-order-dual-browser-live-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task448-tree-resync-recovery-dual-browser-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task449-tree-sse-reconnect-snapshot-recovery-smoke.js

完成标准:

  • 双浏览器页面、文件、垃圾箱操作不刷新页面也能同步。
  • WS 主链可用时 SSE 只作为 fallback。
  • resync 是异常恢复路径,不是每次 delta 后的默认补偿。

7. Phase A6agent 文件编辑权限与 audit 收口

目标:

Hermes / Reasonix 只能在 allowed roots 内编辑文件,写前受版本约束,写后 watcher / audit / projection 能同步。

7.1 当前代码锚点

  • rust/crates/core-protocol/src/ai.rs
    • AiAccessScope
    • allowed_roots
  • rust/crates/mnote-web/src/routes/hermes_client.rs
    • acp_allowed_roots_env_for_payload
    • local_agent_audit_collect_snapshot
    • local_agent_audit_finalize_run
  • rust/crates/mnote-web/src/routes/hermes_tools.rs
    • local_agent_audit_record_write_rejected
    • local_agent_audit_record_tool_write
  • rust/crates/mnote-web/src/hermes_tools/doc.rs
  • rust/crates/mnote-web/src/hermes_tools/page.rs

7.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/edit_file_tool.rs
    • design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/read_file_tool.rs
    • design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/write_file_tool.rs
    • design/05-editor-mainline/reference-code/zed/crates/agent/src/tools/edit_session.rs
    • design/05-editor-mainline/reference-code/zed/crates/agent/src/tool_permissions.rs
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/src-tauri/src/commands/validation.rs
    • design/05-editor-mainline/reference-code/sidex-main/src-tauri/src/commands/fs.rs

7.3 顺序任务

  • 盘点所有 agent 写入口。

    • 搜索命令:rg -n "mnote.doc.markdown_edit|mnote.page.save|mnote.block|allowed_roots|AiAccessScope|write_rejected|agent_audit" rust/crates/mnote-web/src rust/crates/core-protocol/src -S
    • 完成验收:列出 Hermes tool、Reasonix/ACP、agent native file edit、MNote tool 写入入口。
  • allowed roots 校验统一到一个 Rust helper。

    • 完成验收:所有写入口共用同一套 root canonicalization、symlink escape、read/write permission 校验。
  • agent 写入前读取当前 file version。

    • 完成验收:MNote tool 写入必须携带 expectedFileVersionagent native 写入完成后必须进入 audit + watcher 同步路径。
  • audit event 统一 run id 和 changed files 结构。

    • 重点文件:rust/crates/mnote-web/src/routes/hermes_client.rs
    • 完成验收:agent native 写入和 MNote tool 写入可归入同一个 run audit。

7.4 验收

  • allowed roots env 测试通过。

    • 命令:cargo test -p mnote-web acp_allowed_roots -- --nocapture
  • audit 单测通过。

    • 命令:cargo test -p mnote-web local_agent_audit_snapshot_detects_changed_files -- --nocapture
    • 命令:cargo test -p mnote-web hermes_tools_markdown_edit_shared_read -- --nocapture
    • 命令:cargo test -p mnote-web hermes_tools_page_save_local_folder_writes_markdown_file -- --nocapture
  • changed files smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task453-local-folder-page-ai-changed-files-smoke.js

完成标准:

  • read grant 下写入被拒绝并记录 audit。
  • write grant 下写入后 UI 能显示 changed files。
  • agent 不能通过 symlink 或 .. 逃出 allowed roots。

8. Phase A7command context / context key 最小落地

目标:

File Tree / Page Tree / Object Tab / Editor selection 贡献统一 command context,右键菜单和快捷键不再各自临时判断。

8.1 当前代码锚点

  • rust/crates/mnote-web/src/ssr/pages/layout.rs
  • rust/crates/mnote-web/src/routes/tree.rs
  • rust/crates/core-protocol/src/command.rs

8.2 参考代码位置

  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/platform/contextkey
    • design/05-editor-mainline/reference-code/vscode/src/vs/platform/commands
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-keymap/src/context.rs
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-keymap/src/resolver.rs
  • Lapce
    • design/05-editor-mainline/reference-code/lapce/lapce-app/src/command.rs
    • design/05-editor-mainline/reference-code/lapce/lapce-app/src/keypress/loader.rs

8.3 顺序任务

  • 盘点当前菜单、快捷键、按钮 enablement 条件。

    • 搜索命令:rg -n "disabled|aria-disabled|context|shortcut|keydown|menu|right-click|data-action" rust/crates/mnote-web/src/ssr/pages/layout.rs -S
    • 完成验收:列出至少 filetree、pagetree、editor、AI panel 的条件来源。
    • 执行记录(Batch C Worker CFileTree 右键菜单(delete-trash/rename/new-file/new-folder/paste-into 共 5 项,均携带 when)和 Delete/Backspace 快捷键已审计并完成上下文接入。AI panel 条件由 ai.canWrite 在 hermes_tools 守卫中消费。
  • 定义 MNote 最小 command context。

    • 完成 keyworkspace.sourceKindworkspace.readonlytree.focusKindtree.selectionCounttree.selectionResourceKindeditor.dirtyeditor.hasSelectionai.canWrite 共 8 个 key。
    • 完成验收:这些 key 已覆盖当前右键菜单、快捷键和 AI write guard enablement。
    • 代码证明rust/crates/core-protocol/src/command.rsCommandContext 结构体包含全部 8 个字段;7 个单测覆盖 when 求值全路径。
  • 先在 Rust 侧定义 context schema,再让前端消费。

    • Rust 侧:core-protocol/src/command.rsCommandContext + WhenExprNode + evaluate_when / check_when / is_command_enabled
    • 前端侧(SSR layout.rs):buildSidebarFileTreeContext() + evaluateSidebarFileTreeWhen() 两个 JS 等价物用于右键菜单启禁。
    • 完成验收:FileTree 右键菜单和 Delete/Backspace 共享同一 evaluateSidebarFileTreeWhen 路径。

8.4 验收

  • command context 单测覆盖 when 判断。

    • 命令:cargo test -p core-protocol command_context -- --nocapture
    • 结果(2026-05-217 passed — 覆盖 key、!key==!=&&||、括号分组、number comparison、parse error fallback、ai.canWrite gate、workspace.readonly gate。
  • 文件树 DnD / readonly conflict smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task431-vscode-explorer-dnd-readonly-conflict-smoke.js
    • 证据tmp/task431-vscode-explorer-dnd-readonly-conflict-smoke/result.jsonok: truereadonly-target 和 readonly-source 均返回 400。

完成标准:

  • 同一命令在菜单、快捷键、按钮上使用同一 context 判断。
    • FileTree 右键菜单(delete-trash/rename/new-file/new-folder/paste-into)与 Delete/Backspace 快捷键共享 evaluateSidebarFileTreeWhen 路径。
    • 保留的缺口editor/object tab 上下文尚未接入 command contextAI tool 写入守卫 ensure_write_authorized 是独立路径(读 args.commandContext,非前端 context key)。
  • readonly / read grant / selected resource kind 的禁用态一致。
    • FileTree 右键菜单 readonly 禁用已通过 !workspace.readonly when 表达式统一实现。

9. Phase B1:分享与同步闭环

目标:

个人本地空间默认隔离,显式分享后才产生 shared workspace / shared AI session。

9.1 当前代码锚点

  • rust/crates/mnote-web/src/routes/local_access_policy.rs
  • rust/crates/mnote-web/src/routes/hermes_client.rs
  • rust/crates/core-protocol/src/ai.rs
  • recycle/20260522-convex-runtime-retirement/infra/convex/(历史 Convex 自托管对照;不作为 active 部署入口)

9.2 参考代码位置

  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/platform/files
  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/collab
    • 仅参考权限和协作边界,不采用完整协作产品。

9.3 顺序任务

  • 定义 share grant 与 local access grant 的关系。

    • 完成验收:share grant 不自动扩大本机文件系统权限。
  • shared AI session 只消费 share grant 允许的资源。

    • 完成验收:shared AI session 不能访问 owner 本机未授权 root。
  • 同步 cache 目录设计。

    • 完成验收:cache 中保留来源、版本、actor、权限、冲突信息。
  • 同步冲突复用 Phase A2 冲突 UI。

    • 完成验收:冲突报告包含 local、remote、base、actor。

9.4 验收

  • 单测:share read 不允许写入。
  • 单测:shared AI session 不扩大 workspace root。
  • browser smoke:共享页面只读用户无法通过 AI 写入正文。

完成标准:

  • share / sync 不破坏 local-first 权限模型。
  • shared AI session 不能越权读写。

10. Phase B2simplemindmap / office Resource Tree 产品化

目标:

simplemindmap / office 是 Resource Tree 对象,Markdown 正文只保留链接或嵌入引用。

10.1 当前代码锚点

  • rust/crates/mnote-web/src/routes/mindmap_api.rs
  • rust/crates/mnote-web/src/routes/mindmap_shell.rs
  • rust/crates/mnote-web/src/ssr/pages/mindmap.rs
  • rust/crates/mnote-web/src/routes/tree.rs
  • rust/crates/bridge-runtime/src/lib.rs
  • src/components/onlyoffice/

10.2 参考代码位置

  • Zed
    • design/05-editor-mainline/reference-code/zed/crates/project_panel/src/project_panel.rs
  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/file_tree.rs

10.3 顺序任务

  • 盘点 simplemindmap object identity、保存路径、打开路径。

    • 搜索命令:rg -n "mindmap|tree.resource.mindmap|resource:mindmap|mindmapId" rust/crates src -S
    • 完成验收:列出所有 mindmap 创建、打开、保存、删除路径。
  • 盘点 office object identity、保存路径、打开路径。

    • 搜索命令:rg -n "onlyoffice|office|tree.resource.office|resource:office|assetId" rust/crates src -S
    • 完成验收:列出所有 office 创建、打开、保存、删除路径。
  • 统一资源生命周期到 tree.resource.*

    • 完成验收:rename / move / archive / restore / purge 不再走 document command。
  • Markdown 中只写资源引用。

    • 完成验收:mindmap / office 内容不塞回 .md 正文真相。

10.4 验收

  • 单测:resource rename 不走 document command。
  • 单测:mindmap resource 删除 / 恢复不破坏 markdown 页面。
  • browser smokemindmap 长中文保存和 index.md 不互相污染。
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task443-filetree-mindmap-click-active-row-smoke.js
    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task445-filetree-mindmap-switch-no-flicker-smoke.js

完成标准:

  • Page Tree 只做页面导航投影。
  • File Tree 能显示资源行。
  • Resource Tree 才是资源归属真相。

11. Phase C1:旧 Convex 数据迁移产品化

目标:

把旧 Convex workspace 迁移成本变成可视、可回滚、可验证的产品流程。

11.1 当前代码锚点

  • rust/crates/storage-convex-bridge/src/mapping.rs
  • rust/crates/mnote-web/src/transport/convex.rs
  • rust/crates/mnote-web/src/routes/local_folder_source.rs
  • scripts/task444-convex-workspace-export-local-fixture-smoke.js

11.2 参考代码位置

  • VS Code
    • design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/fileImportExport.ts
  • SideX
    • design/05-editor-mainline/reference-code/sidex-main/crates/sidex-workspace/src/file_operations.rs

11.3 顺序任务

  • 设计 dry run 导出计划。

    • 完成验收:计划列出页面、资源、附件、目标路径、冲突项,不写文件。
  • 导出前生成 backup / manifest。

    • 完成验收:manifest 能记录本次新增、覆盖、跳过、失败。
  • 目标 root 同名冲突不覆盖。

    • 完成验收:生成冲突报告,用户明确选择前不写入。
  • 回滚按 manifest 删除新增或恢复备份。

    • 完成验收:回滚后 root 回到导出前状态。
  • 导出完成后重建本地索引。

    • 完成验收:迁移后页面可搜索,资源引用可查。

11.4 验收

  • Convex fixture 导出 smoke 通过。

    • 命令:PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task444-convex-workspace-export-local-fixture-smoke.js
  • 新增 smoke:同名文件冲突时不覆盖。

  • 新增 smoke:回滚后 root 回到导出前状态。

完成标准:

  • 迁移支持 dry run。
  • 迁移支持备份、冲突报告、回滚。
  • 迁移后 local index 可用。

12. 每阶段统一收尾验收

每完成一个 Phase,执行:

  • cargo fmt --check --all --manifest-path rust/Cargo.toml
  • git diff --check -- <changed-files>
  • 与阶段相关的 Rust 单测。
  • 与阶段相关的 browser smoke。
  • npm run check:local-first-convex-guard
  • 把验证证据写回本 checklist。

阶段迁移到 done/ 的标准:

  • checklist 项全部勾选。
  • 真实代码已落地。
  • 单测与 smoke 有证据。
  • 不再依赖临时 compat 作为新增能力主路径。