Files
mnote/design/01-tree-first-graph-kernel/process/1-6-next-phase-gap-closure-checklist-v1.md
T

248 lines
15 KiB
Markdown
Raw Normal View History

2026-05-20 10:43:38 +08:00
# 1-6 [process] 下一阶段缺口补齐 checklist v1
> 创建时间:2026-05-19
>
> 当前状态:`PARTIALLY_DONE`Reasonix 已补 A2/A7 基础设施与 A2 保存/watcher 接入;A2 浏览器刷新可见读回、A0 browser smoke、A7 UI 接入、B2/C1 产品化仍未闭环)
>
> 上位依据:
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-5-next-phase-sequential-execution-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-4-next-phase-execution-roadmap-v1.md`
2026-05-21 10:19:02 +08:00
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md`
2026-05-20 10:43:38 +08:00
>
> 目的:基于 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"}`);browser smoke 尚未复跑。
- [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 个新集成测试覆盖运行时入口。
- [ ] **Gap A2(浏览器可见闭环)**: Codex 浏览器复核显示 `POST /api/page-body/write` 200、磁盘 `.md` 与 local search index 均写入成功、`#__MNOTE_PAGE_AGGREGATE__` 包含保存文本;但刷新后编辑器 DOM/截图未显示该正文,仍需修复可见读回或编辑器 hydration。
- [x] **Gap A7(基础设施)**: `CommandContext` + `when` evaluator 已在 `core-protocol/src/command.rs` 实现。7 个单测全部通过(含 3 个必补测试)。
- [ ] **Gap A7UI/命令接入)**: File Tree 右键菜单、快捷键、AI 写入能力尚未消费 `CommandContext`
- [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"}`
- 验收:通过 ✅
- [ ] 冲突 UI smoke — `task451-local-markdown-conflict-resolution-ui-smoke.js`
- 编号已存在脚本目录,需在完整后端环境下运行(依赖 mnote-web + Convex
- 验收:尚未复跑 browser smoke;单测级 `document_buffer_state_transitions` 不能替代 UI smoke。
- [ ] 本地搜索索引 smoke — `task452-local-search-index-browser-smoke.js`
- 编号已存在脚本目录
- 验收:尚未复跑 browser smoke。
- [ ] 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 单元路径。
### 1.2 收尾
- [x] guard 输出已记录(见上)
- [ ] browser smokes 需完整后端环境运行(mnote-web + Convex + Playwright
- [ ] 失败归属:无失败
---
## 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
- [ ] conflict UI 数据源改为 buffer stateAPI 已就绪,未接入
- [ ] 浏览器可见读回:保存后磁盘与 PageAggregate 已更新,但刷新后 tiptap/editor DOM 未显示保存正文
### 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`
- [ ] **未完成**`documents/save` 的 conflict UI 数据源尚未改为 buffer state 查询
- [ ] **未完成**:浏览器刷新后编辑器可见正文未读回;证据截图:`reasonix-a2-after-refresh-text-missing.png`
### 2.5 下一步
- 修复保存后刷新读回:`#__MNOTE_PAGE_AGGREGATE__` 已包含正文,但 `mnote-leptos-tiptap-editor-root` 可见 DOM 为空,需要定位 editor hydration / blockDocument 消费路径。
- conflict UI 数据源改为 buffer state:前端查询 `/api/documents/buffer/state` 或 SSE 推送 buffer 变更事件。
---
## 3. Gap A7:落地 command context / context key — 🔄 基础设施完成,UI/命令接入未完成
### 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
- [ ] 把 File Tree 右键菜单接入 context`CommandContext``is_command_enabled` 已提供基础设施,但尚未在 SSR layout 中使用
- [ ] 把快捷键接入 context:基础设施已就绪,未接入
- [ ] 把 AI 写入能力接入 context`ai.canWrite` key 已定义,未在 hermes_tools 中消费
### 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 的禁用态可测试
- [ ] **未完成**:当前 UI 中同一命令的多份 enablement 判断尚未统一
- [ ] **未完成**:菜单、按钮、快捷键可用性尚未统一
### 3.5 下一步
`layout.rs` 的右键菜单和 `hermes_tools` 的写入守卫中引入 `is_command_enabled`
---
## 4. Gap B2Resource 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`
- [ ] `mindmap_resource_trash_restore_keeps_markdown_body` — 部分覆盖:
- `mindmap_delete_restore_keeps_markdown_reference_out_of_lifecycle_command` ✅(验证 mindmap 生命周期不携带 documentId 从而不影响 markdown 页面)
- 尚未验证文档正文在 trash/restore 后是否完整
- [x] `local_agent_audit_snapshot_detects_resource_files` — 通过 ✅
- [ ] browser smokes`task443``task445` 需 Playwright 后端环境
### 4.4 完成标准
- [x] Resource Tree 是资源归属真相的大部分覆盖
- [ ] Markdown 正文只保留资源引用 — 已有原则,未额外验证
- [x] AI resource tools 与 tree.resource 生命周期一致 — 验证通过
---
## 5. Gap C1Convex 迁移产品化补证据 — 🔄 部分完成
### 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 验证通过 ✅
### 5.3 必补测试
- [x] `task444-convex-workspace-export-local-fixture-smoke.js` — 通过 ✅
- [ ] 新增 smokedry run 不写文件 — `--dry-run` 已支持,需额外 smoke 验证
- [ ] 新增 smoke:同名冲突不覆盖 — 已有冲突报告逻辑,需 smoke 验证
- [ ] 新增 smokerollback 恢复导出前状态 — 已支持,需 smoke 验证
---
## 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`
- [ ] `task451-local-markdown-conflict-resolution-ui-smoke.js`
- [ ] `task452-local-search-index-browser-smoke.js`
- [ ] `task453-local-folder-page-ai-changed-files-smoke.js`
- [ ] `task443-filetree-mindmap-click-active-row-smoke.js`
- [ ] `task445-filetree-mindmap-switch-no-flicker-smoke.js`
### 6.3 总完成率
| Gap | 状态 | 关键产出 | 剩余 |
|-----|------|----------|------|
| A0 | 🔄 部分 | guard 通过,smoke 脚本已存在 | browser smokes 未复跑 |
| A2 | 🔄 运行时接入完成,浏览器闭环未完成 | `BufferStore` 实现 + 11 tests;保存请求 200;磁盘和 PageAggregate 写入成功 | 刷新后 editor DOM 未显示正文;conflict UI 未接 buffer state |
| A7 | 🔄 基础设施完成 | `CommandContext` + when evaluator + 7 tests | UI/快捷键/菜单接入 |
| B2 | 🔄 部分 | 资源生命周期 + agent audit 测试通过 | mindmap body 测试、browser smokes |
| C1 | 🔄 部分 | export/rollback/dry-run 脚本 + smoke 通过 | 额外 smoke 验证 |