# 1-6 [process] 下一阶段缺口补齐 checklist v1

> 创建时间：2026-05-19
>
> 当前状态：`DONE`（A0/A2/A7/B2/C1 已完成；`task431` 只读 DnD smoke 仅作为可选回归项，不再阻塞本清单归档）
>
> 2026-05-22 归档治理补充：上位路线图 `1-4` 与顺序清单 `1-5` 已移动到 `reference/`；本文只保留真实仍需收口的缺口与证据尾项，不再承接完整下一阶段路线图职责。
>
> 上位依据：
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-5-next-phase-sequential-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-4-next-phase-execution-roadmap-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md`
>
> 目的：基于 Reasonix 执行汇总和本轮核对结果，列出仍不能标完成的缺口，形成可继续顺序执行的补充清单。

---

## 0. 当前核对结论

本轮已确认：

- [x] `ObjectWorkspacePath` 已在 `core-protocol` 定义并导出。
- [x] local folder projection 已输出 `resourceMeta.workspacePath`。
- [x] 前端 `fileObjectIdentity` 已优先读取 `resourceMeta.workspacePath.objectIdentity`。
- [x] `DocumentBuffer` / `DocBufferDirtyState` 已在 `core-protocol` 定义并有状态机测试。
- [x] `mnote.mindmap.*` / `mnote.office.*` Hermes resource tools 已出现，且最小测试通过。

本轮 Reasonix 执行后新增：

- [x] **Gap A0（主路径完成）**: local-first guard 已通过 ✅（`npm run check:local-first-convex-guard` → `{ok: true, guard: "local-first-convex"}`）；`task451` / `task452` / `task453` 已复跑，旧 `task431` 仅保留为可选回归项。
- [x] **Gap A2（基础设施+运行时接入）**: `BufferStore` 已在 `rust/crates/mnote-web/src/document_buffer_store.rs` 实现，并加入 `AppState.buffer_store`。运行时接入完成：`write_local_markdown_page_body` → `mark_saved`、watcher → `mark_external_modified`、Hermes tools → 共享 helper。11 个单测全部通过（含 3 个新集成测试）。
- [x] **Gap A2（运行时接入—完成）**: `write_local_markdown_page_body` 已接入 `BufferStore.mark_saved()`；`documents.rs` `page_body_write` 和 `save` 路由已传递 `state.buffer_store`；Hermes `doc_apply_block_ops` 和 `page_command` 已传递 `state.buffer_store`；watcher 已在 `spawn_local_folder_watcher` 内调用 `mark_external_modified`。3 个新集成测试覆盖运行时入口。
- [x] **Gap A2（浏览器可见闭环）**: Codex 复核新增 `task484-local-folder-page-body-refresh-readback-smoke.js`，验证 `POST /api/page-body/write` 后磁盘 `.md`、Page Aggregate、刷新后的 ProseMirror 均读回新正文；旧的“刷新后 editor DOM 未显示正文”证据已判定为过期。
- [x] **Gap A7（基础设施）**: `CommandContext` + `when` evaluator 已在 `core-protocol/src/command.rs` 实现。7 个单测全部通过（含 3 个必补测试）。
- [x] **Gap A7（UI/命令接入）**: File Tree 右键菜单、Delete/Backspace 快捷键、AI 写入能力已消费 `CommandContext` / `workspace.readonly` / `ai.canWrite`。
- [x] **Gap B2（部分）**: `resource_rename_uses_resource_command_not_document_command` 测试通过；`local_agent_audit_snapshot_detects_resource_files` 通过；mindmap 生命周期测试通过。
- [x] **Gap C1（部分）**: `scripts/task444-convex-workspace-export-local-fixture-smoke.js` 通过；`export-convex-workspace-to-local.js` 既有 `--dry-run`、`--manifest`、`--conflict-report`、`--rollback` 能力已确认，但本轮未新增对应 smoke。
- [x] **core-protocol 全量测试**: 41 单元 + 6 editor bridge + 2 resource tree = 49 通过 ✅
- [x] **mnote-web 相关测试**: BufferStore 8 通过 + resource_trash 6 通过 + audit 2 通过 = 16 通过 ✅

---

## 1. Gap A0：补齐基线验证证据 — 🔄 部分完成

### 1.1 必跑命令

- [x] 运行 local-first guard。
  - 命令：`npm run check:local-first-convex-guard`
  - 结果：`{"ok": true, "checkedLines": 1, "guard": "local-first-convex"}`
  - 验收：通过 ✅

- [x] 冲突 UI smoke — `task451-local-markdown-conflict-resolution-ui-smoke.js`
  - 编号已存在脚本目录，需在完整后端环境下运行（依赖 mnote-web + Convex）
  - 验收：已复跑 browser smoke；单测级 `document_buffer_state_transitions` 不能替代 UI smoke。
  - **执行记录（2026-05-21, Batch B Worker C）**：✅ **PASS** — 4/4 子步骤全部通过（accept-disk, keep-current, merge-save, agent-conflict-source）。结果文件：`tmp/task451-local-markdown-conflict-resolution-ui-smoke/result.json`

- [x] 本地搜索索引 smoke — `task452-local-search-index-browser-smoke.js`
  - 编号已存在脚本目录
  - 验收：已复跑 browser smoke。
  - **执行记录（2026-05-21, Batch B Worker C）**：❌ **FAIL** — `/api/search/documents` 返回 200 结果正确，但 page-settings 本地索引 panel（backlinks/tags）30s 超时未渲染。归因：**UI 渲染回归**。结果文件：`tmp/task452-local-search-index-browser-smoke/result.json`
  - **Codex 复核（2026-05-21）**：✅ **PASS** — 诊断显示 API 和 UI 均已渲染，失败来自 smoke 仍期待 frontmatter 标题 `Search Smoke`；当前索引面板按路径口径展示 `README` / `README.md` 和链接片段。已更新断言并实跑通过。

- [x] agent changed files smoke — `task453-local-folder-page-ai-changed-files-smoke.js`
  - 编号已存在脚本目录
  - 验收：已复跑 browser smoke；`local_agent_audit_snapshot_detects_changed_files` 和 `detects_resource_files` 只能覆盖 audit 单元路径。
  - **执行记录（2026-05-21, Batch B Worker C）**：✅ **PASS** — capturedKinds: session/run/events 全部捕获。结果文件：`tmp/task453-local-folder-page-ai-changed-files-smoke/result.json`
  - **Codex 复核（2026-05-22）**：✅ **PASS** — 已扩展为 local-first AI 前台同步 smoke；clean path 验证 Hermes `run.completed.agentAudit.changedFiles` 后工具卡、磁盘 `.md`、Page Aggregate、ProseMirror 均出现 marker 且不进冲突态；dirty path 验证同一路径触发 `external-change-conflict`、冲突面板显示 agent run、冲突信封包含 `externalActor / dirtyState / bufferFileVersion`，diff 同时显示本地未保存 token 与 AI 写盘 token。

### 1.2 收尾

- [x] guard 输出已记录（见上）
- [x] browser smokes 已完成主路径复跑；`task443` / `task445` 已迁移到 local-first fixture 并作为归档证据。
- [x] 失败归属：本轮已无 A0 smoke 失败；`task452` 为旧断言假失败

---

## 2. Gap A2：把 DocumentBuffer 接入运行时 BufferStore — ✅ 完成

### 2.1 当前代码锚点（更新后）

- `rust/crates/mnote-web/src/document_buffer_store.rs` — **新增**：`BufferStore` + `BufferKey` 实现
- `rust/crates/mnote-web/src/app.rs` — `buffer_store: BufferStore` 已加入 `AppState`
- `rust/crates/mnote-web/src/lib.rs` — `pub mod document_buffer_store` 已注册
- `rust/crates/core-protocol/src/kernel.rs` — `DocumentBuffer` / `DocBufferDirtyState` / `ObjectWorkspacePath`（已有未改）

### 2.2 顺序任务完成情况

- [x] 新增运行时 `BufferStore` owner：`rust/crates/mnote-web/src/document_buffer_store.rs`，通过 `AppState.buffer_store` 持有
- [x] 定义 buffer key：以 `ObjectWorkspacePath` 的 `workspace_id + source_kind + root_uri + relative_path + document_id` 作为稳定 `BufferKey`
- [x] 接入 tiptap 保存链：`write_local_markdown_page_body` / `documents.rs` `save` 路由已调用 `state.buffer_store.mark_saved()`
- [x] 接入外部文件变更 watcher：`spawn_local_folder_watcher` 已通过 `buffer_store.mark_external_modified()` 更新对应 buffer
- [x] 接入 Hermes/Reasonix 写入后状态更新：`hermes_tools/doc.rs` 和 `hermes_tools/page.rs` 已通过共享 helper `write_local_markdown_page_body` 自动消费 BufferStore
- [x] conflict UI 数据源改为 buffer state：冲突信封已包含 `externalActor / dirtyState / bufferFileVersion`，`task451` 已覆盖
- [x] 浏览器可见读回：`task484-local-folder-page-body-refresh-readback-smoke.js` 已验证保存后刷新 ProseMirror 可见正文不丢失

### 2.3 必补测试

- [x] `document_buffer_reuses_workspace_path_key` — 通过 ✅
- [x] `document_buffer_marks_external_modified_for_clean_buffer` — 通过 ✅
- [x] `document_buffer_marks_stale_for_dirty_buffer` — 通过 ✅
- [x] `document_buffer_mark_saved_after_page_body_write` — 通过 ✅
- [x] 额外测试：`document_buffer_different_paths_different_keys` ✅
- [x] 额外测试：`document_buffer_init_buffer_sets_file_version` ✅
- [x] 额外测试：`document_buffer_mark_dirty_and_saved_round_trip` ✅
- [x] 额外测试：`document_buffer_reuses_across_multiple_get_or_create_calls` ✅

### 2.4 当前完成标准

- [x] `DocumentBuffer` 已有 mnote-web runtime `BufferStore` owner
- [x] `BufferKey` 可稳定区分不同文件
- [x] 11 个单测覆盖了关键 path + state transitions + save round-trip + 运行时入口
- [x] **已完成**：tiptap/保存路由/Hermes 写入链已通过 `write_local_markdown_page_body` 统一消费 `BufferStore`
- [x] **已完成**：watcher 已通过 `spawn_local_folder_watcher` 调用 `mark_external_modified`
- [x] **已完成**：conflict UI 数据源已改为 buffer state 查询；`save_local_markdown_page_with_buffer_store` 在冲突发生时从 BufferStore 查询 `externalActor`、`dirtyState`、`bufferFileVersion` 并加入冲突信封；`/api/documents/buffer-state` 端点提供显式 buffer 状态查询；`document_page_shell` 在打开 local_folder 文档时调用 `init_buffer` 初始化 file_version。task451 smoke 已扩展为在每次冲突后验证信封包含这些 BufferStore 字段。
- [x] **已完成**：浏览器刷新后编辑器可见正文读回；验证 `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task484-local-folder-page-body-refresh-readback-smoke.js`

### 2.5 下一步

- 保存后刷新读回已由 `task484` 复核通过；后续若复现新问题，应以该 smoke 为回归入口。
- conflict UI 数据源已从纯前端猜测改为 BufferStore 信封 + `/api/documents/buffer-state` 端点。后续若需要实时更新（SSE 推送 buffer 变更事件）可在此基础上扩展。

---

## 3. Gap A7：落地 command context / context key — ✅ 主路径完成

### 3.1 当前代码锚点（更新后）

- `rust/crates/core-protocol/src/command.rs` — **已扩展**：新增 `CommandContext`、`WhenExprNode`、`parse_when_expr`、`evaluate_when`、`check_when`、`is_command_enabled`
- `rust/crates/core-protocol/src/lib.rs` — **已更新**：导出所有 command context 类型和函数

### 3.2 顺序任务完成情况

- [x] 定义最小 `CommandContext` 结构：包含 `workspace.sourceKind`、`workspace.readonly`、`tree.focusKind`、`tree.selectionCount`、`tree.selectionResourceKind`、`editor.dirty`、`editor.hasSelection`、`ai.canWrite` 共 8 个 key
- [x] 实现最小 `when` evaluator：支持 `key`、`!key`、`key == value`、`key != value`、`&&`、`||`、括号分组（完整的递归下降解析器 + AST evaluator）
- [x] **File Tree 右键菜单接入 context**（Batch C Worker C）：在 SSR `layout.rs` 的 SIDEBAR_TREE_JS 中新增 `buildSidebarFileTreeContext()` 和 `evaluateSidebarFileTreeWhen()` 两个 JS 等价物。FileTree/Asset/Page 右键菜单的 `delete-trash`、`rename`、`new-file`、`new-folder`、`paste-into` 均已携带 `when: '!workspace.readonly'`。菜单构建时评估 when 表达式，命中时设置 `disabled: true` 并调整 title。workspace readonly 通过 `<html data-mnote-workspace-readonly>` 属性控制，默认 false。
- [x] **Delete/Backspace 快捷键接入 context**（Batch C Worker C）：keydown handler 中 Delete/Backspace 分支新增 `buildSidebarFileTreeContext('filetree')` + `evaluateSidebarFileTreeWhen(delCtx, '!workspace.readonly && tree.selectionCount')` 守卫。只读或无选中时阻止动作。
- [x] 把 AI 写入能力接入 context：`ai.canWrite` key 已定义，并已在 hermes_tools 写入守卫中消费 `args.commandContext` / `args.command_context` 的 `ai.canWrite` 与 `workspace.readonly`。

### 3.3 必补测试

- [x] `command_context_when_clause` — 通过 ✅（覆盖 key、!key、==、!=、&&、||、括号分组）
- [x] `command_context_disables_write_commands_for_readonly_workspace` — 通过 ✅
- [x] `command_context_filters_resource_commands_by_kind` — 通过 ✅
- [x] `command_context_default_is_allow` — 通过 ✅
- [x] `command_context_number_comparison` — 通过 ✅
- [x] `command_context_parse_error_returns_default` — 通过 ✅
- [x] `command_context_ai_can_write_gates_ai_actions` — 通过 ✅

### 3.4 当前完成标准

- [x] 最小 `CommandContext` 定义 + `when` evaluator 可工作
- [x] readonly / grant / resource kind 的禁用态可测试
- [x] **FileTree 右键菜单已接入**（Batch C Worker C）：delete-trash、rename、new-file、new-folder、paste-into 携带 `when: '!workspace.readonly'`
- [x] **Delete/Backspace 快捷键已接入**（Batch C Worker C）：keydown handler 中有 `!workspace.readonly && tree.selectionCount` 守卫
- [x] 下载、多选删除、粘贴、只读阻断的主路径 smoke 已由 `task471` / `task476` 在 Batch H 复跑覆盖；`task431` 作为更旧 DnD readonly smoke 仍保留为可选回归项。
- [x] **已完成**：AI 写入能力 (`ai.canWrite`) 已接入 hermes_tools 写入守卫；`mnote.block.*`、`mnote.doc.markdown_edit`、`mnote.page.*`、`mnote.artifact.*`、`mnote.mindmap.apply_ops` 写入链共享 `ensure_write_authorized`，只读 scope、`workspace.readonly=true` 或 `ai.canWrite=false` 均会拒绝写入。

### 3.5 下一步

- `layout.rs` 右键菜单：已引入 `evaluateSidebarFileTreeWhen`（Batch C Worker C 完成）
- Delete/Backspace：已接入（Batch C Worker C 完成）
- hermes_tools 写入守卫：已消费 `ai.canWrite` / `workspace.readonly` command context；后续若前端新增更多 AI 写入口，必须把同一份 `commandContext` 透传到 tool args。
- 归档前可选补跑 `task431-vscode-explorer-dnd-readonly-conflict-smoke.js`，但它不再代表 A7 主路径缺失。

### 3.6 Batch F 复核记录

- 2026-05-21：Codex 将 Hermes 写入守卫收口为 `ensure_write_authorized`，`ToolCallInput` 从 `args.commandContext` / `args.command_context` 读取 `ai.canWrite` 与 `workspace.readonly`。
- 2026-05-21：`mnote.block.*` / `mnote.doc.markdown_edit` 继续经 `block::ensure_write_contract`，该函数已委托共享守卫；`mnote.page.*`、`mnote.artifact.*`、`mnote.mindmap.apply_ops` 也委托共享守卫。
- 2026-05-21：新增测试覆盖 `ai.canWrite=false` 与 `workspace.readonly=true` 的拒绝路径。

---

## 4. Gap B2：Resource tools 到 Resource Tree 产品化 — 🔄 部分完成

### 4.1 当前代码锚点（已有未改）

- `rust/crates/mnote-web/src/routes/resource_trash.rs` — 媒体 / mindmap / table 生命周期使用 `tree.resource.*` 命令
- `rust/crates/mnote-web/src/routes/hermes_tools.rs`
- `rust/crates/mnote-web/src/hermes_tools/resource.rs`
- `rust/crates/mnote-web/src/hermes_tools/manifest.rs`

### 4.2 顺序任务完成情况

- [x] 明确 resource tool 是辅助入口，不是资源真相 — 文档中已有此约定
- [x] mindmap resource 生命周期走 `tree.resource.*` — 测试验证 ✅
- [x] office resource 生命周期走 `tree.resource.*` — ✅（仅链路存在，需更多测试覆盖）
- [ ] Resource Tree projection 显示资源对象 — 部分完成（filetree 已显示资源行）
- [x] agent audit 包含 resource files — `local_agent_audit_snapshot_detects_resource_files` 通过 ✅

### 4.3 必补测试

- [x] `tree_resource_rename_does_not_emit_document_command` — 被现有测试覆盖：
  - `resource_rename_uses_resource_command_not_document_command` ✅（验证 canonicalCommand 为 `tree.resource.rename` 而非 `tree.node.rename`）
- [x] `mindmap_resource_trash_restore_keeps_markdown_body` — 已覆盖：
  - `mindmap_delete_restore_keeps_markdown_reference_out_of_lifecycle_command` ✅（验证 mindmap 生命周期不携带 documentId 从而不影响 markdown 页面）
  - `local_folder_mindmap_delete_moves_resource_file_to_trash` ✅（2026-05-22 补断言：archive / restore 后 `Page.md` 正文引用保持原文）
- [x] `local_agent_audit_snapshot_detects_resource_files` — 通过 ✅
- [x] browser smokes：`task443`、`task445` 需 Playwright 后端环境
  - **执行记录（2026-05-21, Batch B Worker C）**：❌ **FAIL** — 两个 smoke 均因 `waitForURL` 断言 `/mindmap/` 路由超时，实际导航走的是 `/documents/...?resourceTab=...`。归因：**脚本过时**（mindmap 路由改为 resourceTab，smoke 未同步）。结果文件：`tmp/task443-filetree-mindmap-click-active-row-smoke/result.json`、`tmp/task445-filetree-mindmap-switch-no-flicker-smoke/result.json`
  - **Codex 复核（2026-05-21）**：✅ **PASS** — 已更新为当前 `resourceTab=resource:mindmap:{docId}:{mindmapId}` 断言，两个 smoke 实跑通过。`task445` 仍捕获一次跨文档 mindmap API `400 Bad Request` console error，但 smoke failures 为空，单独保留为后续噪声/边界排查。
  - **Codex 复核（2026-05-22）**：✅ **代码级修复** — `task445` 的 400 不是纯噪声，根因是跨文档后 asset row 打开时沿用了当前 URL 的 document，而不是资源 owner document。已补 `sidebar_filetree_asset_open_uses_owner_document_id` 回归测试，并让 filetree asset row 输出/消费 `data-owner-document-id`；`task445` 同步增加 owner URL 断言。浏览器复跑当前被旧 Convex fixture 阻塞：`workspaces:ensureDefaultWorkspace` function 已退役，返回 502。
  - **Codex 复核（2026-05-22 续）**：✅ **PASS** — `task443` / `task445` 已迁移为 local-first fixture（临时 root + `.mnote/workspace.json` + 本地 `.md` / `.mindmap.json`），不再依赖退役 Convex function。复跑命令：
    - `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`
    - 两者结果均为 PASS，结果文件分别为 `tmp/task443-filetree-mindmap-click-active-row-smoke/result.json`、`tmp/task445-filetree-mindmap-switch-no-flicker-smoke/result.json`。

### 4.4 完成标准

- [x] Resource Tree 是资源归属真相的大部分覆盖
- [ ] Markdown 正文只保留资源引用 — 已有原则，未额外验证
- [x] AI resource tools 与 tree.resource 生命周期一致 — 验证通过

---

## 5. Gap C1：Convex 迁移产品化补证据 — ✅ 完成

### 5.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`
- `scripts/export-convex-workspace-to-local.js`

### 5.2 顺序任务完成情况

- [x] 定义 dry run response — `export-convex-workspace-to-local.js` 支持 `--dry-run` 标识 ✅
- [x] 定义 migration manifest — 支持 `--manifest` 参数 ✅
- [x] 实现同名冲突不覆盖 — 导出时不覆盖已有文件，输出冲突报告 ✅
- [x] 实现 rollback — 支持 `--rollback` 参数 ✅
- [x] 导出完成后重建 local index — task444 smoke 验证通过 ✅
- [x] dry-run/conflict/rollback 独立 smoke — `task455-convex-export-plan-rollback-smoke.js` 三个行为全部通过 ✅

### 5.3 必补测试

- [x] `task444-convex-workspace-export-local-fixture-smoke.js` — 通过 ✅
- [x] 新增 smoke：dry run 不写文件 — `task455` 验证 `--dry-run` 后 pages 目录不存在 ✅
- [x] 新增 smoke：同名冲突不覆盖 — `task455` 验证冲突后 exit(2) + 页面前内容保持 ✅
- [x] 新增 smoke：rollback 恢复导出前状态 — `task455` 验证 rollback 后 pages/assets 均删除 ✅

---

## 6. 最终收尾

### 6.1 验证命令结果

- [x] `cargo test -p core-protocol` — 41+6+2=49 passed ✅
- [x] `cargo test -p mnote-web document_buffer` — 8 passed ✅
- [x] `cargo test -p mnote-web resource_trash` — 6 passed ✅
- [x] `cargo test -p mnote-web local_agent_audit_snapshot` — 2 passed ✅
- [x] `npm run check:local-first-convex-guard` — `{"ok": true}` ✅
- [x] `node scripts/task444-convex-workspace-export-local-fixture-smoke.js` — `{"ok": true}` ✅
- [x] `cargo fmt --check --all --manifest-path rust/Cargo.toml` — 通过 ✅
- [x] `git diff --check -- <changed-files>` — 通过 ✅

### 6.2 Browser smokes（需完整后端环境）

- [ ] `task431-vscode-explorer-dnd-readonly-conflict-smoke.js`
- [x] `task451-local-markdown-conflict-resolution-ui-smoke.js`
- [x] `task452-local-search-index-browser-smoke.js`
- [x] `task453-local-folder-page-ai-changed-files-smoke.js`
- [x] `task443-filetree-mindmap-click-active-row-smoke.js`
- [x] `task445-filetree-mindmap-switch-no-flicker-smoke.js`

### 6.2.1 本次执行结果（Batch B Worker C @ 2026-05-21）

- `task451-local-markdown-conflict-resolution-ui-smoke.js`
  - **PASS** ✅ — 4 个子步骤全部通过：accept-disk、keep-current、merge-save、agent-conflict-source
  - 命令：`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js`
  - 结果：`tmp/task451-local-markdown-conflict-resolution-ui-smoke/result.json`
- `task452-local-search-index-browser-smoke.js`
  - **PASS** ✅ — Codex 复核后更新旧断言；本地索引面板已渲染 backlinks/tags，`README.md`、链接片段和 `#alpha` 可见
  - 命令：`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task452-local-search-index-browser-smoke.js`
  - 结果：`tmp/task452-local-search-index-browser-smoke/result.json`
  - 归因：**脚本断言过时** — 原断言期待 frontmatter 标题，当前索引面板按路径标题展示
- `task453-local-folder-page-ai-changed-files-smoke.js`
  - **PASS** ✅ — clean AI 写入后 Page Aggregate / ProseMirror 前台同步，dirty AI 写入触发 conflict UI 并显示 BufferStore 信封
  - 命令：同上
  - 结果：`tmp/task453-local-folder-page-ai-changed-files-smoke/result.json`
- `task443-filetree-mindmap-click-active-row-smoke.js`
  - **PASS** ✅ — local-first fixture 下，mindmap 资源行点击后 URL 使用 `/documents/...&resourceTab=resource:mindmap:...`，且对应 asset row 选中
  - 命令：`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task443-filetree-mindmap-click-active-row-smoke.js`
  - 结果：`tmp/task443-filetree-mindmap-click-active-row-smoke/result.json`
  - 归因：**脚本过时后已更新并去 Convex fixture 化** — mindmap 已改为 resourceTab 路由，fixture 改为 local_folder
- `task445-filetree-mindmap-switch-no-flicker-smoke.js`
  - **PASS** ✅ — local-first fixture 下，页面和 mindmap 来回切换时 file tree root 稳定，选中态正确；跨文档资源重新打开时 URL pathname 使用资源 owner document
  - 命令：`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task445-filetree-mindmap-switch-no-flicker-smoke.js`
  - 结果：`tmp/task445-filetree-mindmap-switch-no-flicker-smoke/result.json`
  - 归因：**脚本过时后已更新并去 Convex fixture 化** — 400 根因已收口到 ResourceTab owner document URL 同步

### 6.2.2 本次执行汇总

| Smoke | 结果 | 归因 |
|-------|------|------|
| task451 | ✅ PASS | — |
| task452 | ✅ PASS | 脚本断言过时，已按当前路径标题和链接片段语义更新 |
| task453 | ✅ PASS | 已扩展为 AI clean/dirty 前台同步与 conflict UI 证据 |
| task443 | ✅ PASS | 已改为 resourceTab 路由断言，并迁移到 local-first fixture |
| task445 | ✅ PASS | 已改为 resourceTab 路由断言，并迁移到 local-first fixture；ResourceTab owner document URL 已修复 |

---

### 6.3 总完成率

| Gap | 状态 | 关键产出 | 剩余 |
|-----|------|----------|------|
| A0 | ✅ 主路径完成 | guard、task451、task452、task453 通过 | task431 可选复跑 |
| A2 | ✅ 完成 | `BufferStore` 实现 + 11 tests；task451 覆盖 BufferStore 冲突信封；task484 验证保存后磁盘、PageAggregate、刷新后 ProseMirror 全部读回 | — |
| A7 | ✅ 主路径完成 | `CommandContext` + when evaluator + 7 tests；FileTree 菜单、Delete/Backspace、AI 写入守卫接入 | task431 可选复跑 |
| B2 | ✅ 主路径完成 | 资源生命周期 + agent audit 测试通过；mindmap 正文引用保持、ResourceTab owner 修复与 task443/task445 local-first browser 证据已补齐 | Resource Tree projection 产品形态深化另列后续项 |
| C1 | ✅ 完成 | export/rollback/dry-run 脚本 + task444/task455 smoke 全部通过 | — |

归档结论：本清单原本承担的 gap closure 已完成。后续活跃执行转入 `1-8` 的顺序表与 `7-14` 的 AI Markdown 编辑路径收敛，不再把本文件作为 active process。
