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

697 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_id``root_uri``root_id``relative_path``source_kind``object_identity``resource_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_path``file_version``base_content_hash``current_content_hash``dirty_state``external_change_state``last_loaded_at``last_saved_at`
- 完成验收:字段能覆盖 clean、dirty、stale、external modified、deleted 五种状态。
- [ ]`/api/page-body/write` 成为本地 `.md` 正文写入主入口。
- 重点文件:`rust/crates/mnote-web/src/routes/documents.rs`
- 完成验收:本地 markdown 写入必须携带 `expectedFileVersion``documents/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 adapter``test fixture``must 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 写入必须携带 `expectedFileVersion`agent 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 顺序任务
- [x] 盘点当前菜单、快捷键、按钮 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 C**FileTree 右键菜单(delete-trash/rename/new-file/new-folder/paste-into 共 5 项,均携带 `when`)和 Delete/Backspace 快捷键已审计并完成上下文接入。AI panel 条件由 `ai.canWrite` 在 hermes_tools 守卫中消费。
- [x] 定义 MNote 最小 command context。
- 完成 key`workspace.sourceKind``workspace.readonly``tree.focusKind``tree.selectionCount``tree.selectionResourceKind``editor.dirty``editor.hasSelection``ai.canWrite` 共 8 个 key。
- 完成验收:这些 key 已覆盖当前右键菜单、快捷键和 AI write guard enablement。
- **代码证明**`rust/crates/core-protocol/src/command.rs``CommandContext` 结构体包含全部 8 个字段;7 个单测覆盖 when 求值全路径。
- [x] 先在 Rust 侧定义 context schema,再让前端消费。
- Rust 侧:`core-protocol/src/command.rs``CommandContext` + `WhenExprNode` + `evaluate_when` / `check_when` / `is_command_enabled`
- 前端侧(SSR `layout.rs`):`buildSidebarFileTreeContext()` + `evaluateSidebarFileTreeWhen()` 两个 JS 等价物用于右键菜单启禁。
- 完成验收:FileTree 右键菜单和 Delete/Backspace 共享同一 `evaluateSidebarFileTreeWhen` 路径。
### 8.4 验收
- [x] command context 单测覆盖 `when` 判断。
- 命令:`cargo test -p core-protocol command_context -- --nocapture`
- **结果(2026-05-21**7 passed — 覆盖 key、`!key``==``!=``&&``||`、括号分组、number comparison、parse error fallback、`ai.canWrite` gate、`workspace.readonly` gate。
- [x] 文件树 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.json``ok: true`readonly-target 和 readonly-source 均返回 400。
完成标准:
- [x] 同一命令在菜单、快捷键、按钮上使用同一 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)。
- [x] 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 作为新增能力主路径。