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

> 创建时间：2026-05-19
>
> 当前状态：`reference`
>
> 归档说明（2026-05-22）：本文是历史顺序清单，部分条目已被后续 Batch / done 文档覆盖；当前只作为参考，不再作为 active process 队列。
>
> 上位依据：
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-4-next-phase-execution-roadmap-v1.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/done/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 A3：Page 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 A4：tree 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 A5：tree 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 A6：agent 文件编辑权限与 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 A7：command 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 context；AI 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 B2：simplemindmap / 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 smoke：mindmap 长中文保存和 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 作为新增能力主路径。
