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

19 KiB
Raw Blame History

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

创建时间:2026-05-19

当前状态:PARTIALLY_DONEReasonix 已补 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
  • /mnt/Data1T/mnote/design/05-editor-mainline/reference/5-14-zed-lapce-vscode-reference-adoption-matrix-v1.md

目的:基于 Reasonix 执行汇总和本轮核对结果,列出仍不能标完成的缺口,形成可继续顺序执行的补充清单。


0. 当前核对结论

本轮已确认:

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

本轮 Reasonix 执行后新增:

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

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

1.1 必跑命令

  • 运行 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。
    • 执行记录(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
  • 本地搜索索引 smoke — task452-local-search-index-browser-smoke.js

    • 编号已存在脚本目录
    • 验收:已复跑 browser smoke。
    • 执行记录(2026-05-21, Batch B Worker C FAIL/api/search/documents 返回 200 结果正确,但 page-settings 本地索引 panelbacklinks/tags30s 超时未渲染。归因:UI 渲染回归。结果文件:tmp/task452-local-search-index-browser-smoke/result.json
    • Codex 复核(2026-05-21 PASS — 诊断显示 API 和 UI 均已渲染,失败来自 smoke 仍期待 frontmatter 标题 Search Smoke;当前索引面板按路径口径展示 README / README.md 和链接片段。已更新断言并实跑通过。
  • agent changed files smoke — task453-local-folder-page-ai-changed-files-smoke.js

    • 编号已存在脚本目录
    • 验收:已复跑 browser smokelocal_agent_audit_snapshot_detects_changed_filesdetects_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

1.2 收尾

  • guard 输出已记录(见上)
  • browser smokes 需完整后端环境运行(mnote-web + Convex + Playwright
  • 失败归属:本轮已无 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.rsbuffer_store: BufferStore 已加入 AppState
  • rust/crates/mnote-web/src/lib.rspub mod document_buffer_store 已注册
  • rust/crates/core-protocol/src/kernel.rsDocumentBuffer / DocBufferDirtyState / ObjectWorkspacePath(已有未改)

2.2 顺序任务完成情况

  • 新增运行时 BufferStore ownerrust/crates/mnote-web/src/document_buffer_store.rs,通过 AppState.buffer_store 持有
  • 定义 buffer key:以 ObjectWorkspacePathworkspace_id + source_kind + root_uri + relative_path + document_id 作为稳定 BufferKey
  • 接入 tiptap 保存链:write_local_markdown_page_body / documents.rs save 路由已调用 state.buffer_store.mark_saved()
  • 接入外部文件变更 watcherspawn_local_folder_watcher 已通过 buffer_store.mark_external_modified() 更新对应 buffer
  • 接入 Hermes/Reasonix 写入后状态更新:hermes_tools/doc.rshermes_tools/page.rs 已通过共享 helper write_local_markdown_page_body 自动消费 BufferStore
  • conflict UI 数据源改为 buffer stateAPI 已就绪,未接入
  • 浏览器可见读回:task484-local-folder-page-body-refresh-readback-smoke.js 已验证保存后刷新 ProseMirror 可见正文不丢失

2.3 必补测试

  • document_buffer_reuses_workspace_path_key — 通过
  • document_buffer_marks_external_modified_for_clean_buffer — 通过
  • document_buffer_marks_stale_for_dirty_buffer — 通过
  • document_buffer_mark_saved_after_page_body_write — 通过
  • 额外测试:document_buffer_different_paths_different_keys
  • 额外测试:document_buffer_init_buffer_sets_file_version
  • 额外测试:document_buffer_mark_dirty_and_saved_round_trip
  • 额外测试:document_buffer_reuses_across_multiple_get_or_create_calls

2.4 当前完成标准

  • DocumentBuffer 已有 mnote-web runtime BufferStore owner
  • BufferKey 可稳定区分不同文件
  • 11 个单测覆盖了关键 path + state transitions + save round-trip + 运行时入口
  • 已完成tiptap/保存路由/Hermes 写入链已通过 write_local_markdown_page_body 统一消费 BufferStore
  • 已完成watcher 已通过 spawn_local_folder_watcher 调用 mark_external_modified
  • 未完成documents/save 的 conflict UI 数据源尚未改为 buffer state 查询
  • 已完成:浏览器刷新后编辑器可见正文读回;验证 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 数据源改为 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已扩展:新增 CommandContextWhenExprNodeparse_when_exprevaluate_whencheck_whenis_command_enabled
  • rust/crates/core-protocol/src/lib.rs已更新:导出所有 command context 类型和函数

3.2 顺序任务完成情况

  • 定义最小 CommandContext 结构:包含 workspace.sourceKindworkspace.readonlytree.focusKindtree.selectionCounttree.selectionResourceKindeditor.dirtyeditor.hasSelectionai.canWrite 共 8 个 key
  • 实现最小 when evaluator:支持 key!keykey == valuekey != value&&||、括号分组(完整的递归下降解析器 + AST evaluator
  • 把 File Tree 右键菜单接入 contextCommandContextis_command_enabled 已提供基础设施,但尚未在 SSR layout 中使用
  • 把快捷键接入 context:基础设施已就绪,未接入
  • 把 AI 写入能力接入 contextai.canWrite key 已定义,未在 hermes_tools 中消费

3.3 必补测试

  • command_context_when_clause — 通过 (覆盖 key、!key、==、!=、&&、||、括号分组)
  • command_context_disables_write_commands_for_readonly_workspace — 通过
  • command_context_filters_resource_commands_by_kind — 通过
  • command_context_default_is_allow — 通过
  • command_context_number_comparison — 通过
  • command_context_parse_error_returns_default — 通过
  • command_context_ai_can_write_gates_ai_actions — 通过

3.4 当前完成标准

  • 最小 CommandContext 定义 + when evaluator 可工作
  • 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 顺序任务完成情况

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

4.3 必补测试

  • 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 后是否完整
  • local_agent_audit_snapshot_detects_resource_files — 通过
  • browser smokestask443task445 需 Playwright 后端环境
    • 执行记录(2026-05-21, Batch B Worker C FAIL — 两个 smoke 均因 waitForURL 断言 /mindmap/ 路由超时,实际导航走的是 /documents/...?resourceTab=...。归因:脚本过时mindmap 路由改为 resourceTabsmoke 未同步)。结果文件:tmp/task443-filetree-mindmap-click-active-row-smoke/result.jsontmp/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 为空,单独保留为后续噪声/边界排查。

4.4 完成标准

  • Resource Tree 是资源归属真相的大部分覆盖
  • Markdown 正文只保留资源引用 — 已有原则,未额外验证
  • 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 顺序任务完成情况

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

5.3 必补测试

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

6. 最终收尾

6.1 验证命令结果

  • cargo test -p core-protocol — 41+6+2=49 passed
  • cargo test -p mnote-web document_buffer — 8 passed
  • cargo test -p mnote-web resource_trash — 6 passed
  • cargo test -p mnote-web local_agent_audit_snapshot — 2 passed
  • npm run check:local-first-convex-guard{"ok": true}
  • node scripts/task444-convex-workspace-export-local-fixture-smoke.js{"ok": true}
  • cargo fmt --check --all --manifest-path rust/Cargo.toml — 通过
  • 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.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/tagsREADME.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 — capturedKinds: session/run/events 全部捕获
    • 命令:同上
    • 结果:tmp/task453-local-folder-page-ai-changed-files-smoke/result.json
  • task443-filetree-mindmap-click-active-row-smoke.js
    • PASS — 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
    • 归因:脚本过时后已更新 — mindmap 已改为 resourceTab 路由
  • task445-filetree-mindmap-switch-no-flicker-smoke.js
    • PASS — 页面和 mindmap 来回切换时 file tree root 稳定,选中态正确
    • 命令: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
    • 归因:脚本过时后已更新 — 仍有一次 400 console noise,后续单独排查

6.2.2 本次执行汇总

Smoke 结果 归因
task451 PASS
task452 PASS 脚本断言过时,已按当前路径标题和链接片段语义更新
task453 PASS
task443 PASS 脚本过时,已改为 resourceTab 路由断言
task445 PASS 脚本过时,已改为 resourceTab 路由断言;仍有 400 console noise

6.3 总完成率

Gap 状态 关键产出 剩余
A0 🔄 部分 guard、task451、task452、task453 通过 task431 等剩余 browser smokes 未复跑
A2 🔄 运行时接入 + 浏览器读回完成 BufferStore 实现 + 11 teststask484 验证保存后磁盘、PageAggregate、刷新后 ProseMirror 全部读回 conflict UI 未接 buffer state
A7 🔄 基础设施完成 CommandContext + when evaluator + 7 tests UI/快捷键/菜单接入
B2 🔄 部分 资源生命周期 + agent audit 测试通过;task443/task445 通过 mindmap body 测试、跨文档 ResourceTab 400 噪声排查
C1 完成 export/rollback/dry-run 脚本 + task444/task455 smoke 全部通过