batch E: close tail checks and refresh smoke evidence

This commit is contained in:
lix-2026
2026-05-21 17:15:28 +08:00
parent 1e8f5c5816
commit cc91a56603
16 changed files with 1093 additions and 45 deletions
@@ -0,0 +1,125 @@
# 1-12 [process] Batch E P1/P2 尾项执行 checklist v1
> 创建时间:2026-05-21
>
> 当前状态:`PROCESS`
>
> 上位入口:`design/01-tree-first-graph-kernel/process/1-8-mvp-post-process-execution-order-v1.md`
>
> 阶段:Batch E / P1-P2 剩余尾项收口
## 1. 目标
本批次只处理当前仍有明确证据缺口、且可以并行推进的三个小尾项:
1. `3-13` GFM AST 迁移尾项:保存失败状态保留、表格降级策略、`web_shell.rs` 临时适配分支去留判定。
2. `1-6` Gap A2conflict UI 数据源从本地 session 状态进一步接入 `BufferStore` 可查询状态。
3. `1-6` Gap A7 / `1-8` P2.2FileTree 菜单与快捷键最小接入 `CommandContext` enablement 口径。
本批次不扩 AI 主线,不处理 Wolai 对标,不提前实现 Phase C / Review Mode,不改变 local-first / tree-first 口径。
## 2. 已完成追认
- [x] `5-26` resource open resolver 已由 Batch D 完成,并经 `task463-onlyoffice-resolver-smoke.js` 与 Rust 单测复核,已归档到 `design/05-editor-mainline/done/`
- [x] `1-6` Gap A2 保存后刷新可见读回已由 `task484-local-folder-page-body-refresh-readback-smoke.js` 复核通过。
- [x] `1-6` Gap C1 Convex export dry-run / conflict / rollback 已由 `task455-convex-export-plan-rollback-smoke.js` 复核通过。
- [x] `1-6` Gap A2 conflict UI 数据源已接入 `BufferStore` 查询与冲突信封桥接;`/api/documents/buffer-state``document_page_shell` 初始化、`task451` 信封断言均已通过,`task451` 在最新 3000 主进程上已复测通过。
- [x] `1-6` Gap A7 FileTree 右键菜单与 Delete/Backspace 快捷键已接入 `CommandContext` 等价 enablement 逻辑;`task471` / `task476` / `core-protocol command_context` 已通过。
## 3. Reasonix Worker 拆分
### Worker AGFM AST 保存失败与降级策略尾项
Owner
- `design/03-rust-web/process/3-13-rust-web-local-markdown-gfm-ast-parser-migration-v1.md`
- `rust/crates/mnote-web/src/routes/local_folder_source.rs`
- `rust/crates/mnote-web/src/routes/local_markdown_parser.rs`
- `rust/crates/mnote-web/src/routes/web_shell.rs`(只读审查,不能直接修改)
- 可新增或修改一个 `scripts/task48*-local-markdown-save-error-*.js` smoke。
目标:
- 补最小测试或实现,验证保存失败时编辑器状态可保留并显示可解释错误。
- 补表格带 mark 单元格或不支持结构的降级策略测试;若当前行为已经可解释,写入证据并更新 `3-13`
- 只读审查 `web_shell.rs``legacyStylesToTiptapMarks` 等临时适配分支是否仍为必要兼容层;不能安全移除时,把它从“必须移除”改为“保留兼容层并有 TODO 退出条件”。
验收:
- `cargo test -p mnote-web local_markdown -- --test-threads=1`
- `cargo test -p mnote-web web_shell -- --test-threads=1`
- 如新增 smoke`node --check scripts/task48*-local-markdown-save-error-*.js`,并尽量实跑。
当前状态:
- 已有 `task473` / `task455` / `task451` 等结果可表明相邻尾项已处理,但保存失败状态保留与 `web_shell.rs` 兼容层退出条件仍需 Worker A 自己落盘证据。
### Worker BBufferStore conflict UI 数据源
Owner
- `design/01-tree-first-graph-kernel/process/1-6-next-phase-gap-closure-checklist-v1.md`
- `rust/crates/mnote-web/src/document_buffer_store.rs`
- `rust/crates/mnote-web/src/routes/documents.rs`
- `rust/crates/mnote-web/src/routes/web_shell.rs`
- `scripts/task451-local-markdown-conflict-resolution-ui-smoke.js`
目标:
- 为当前打开文档暴露最小 buffer state 查询能力,或把已有 Page Aggregate / session conflict envelope 明确桥接到 `BufferStore` 状态。
- conflict UI 应能读取 editor base version、disk/current version、source actor 或等价字段;不能只靠前端本地临时状态。
- 保持现有 `task451` 的 accept disk / keep current / merge 三条行为不回退。
验收:
- `cargo test -p mnote-web document_buffer -- --test-threads=1`
- `cargo test -p mnote-web local_folder -- --test-threads=1`
- `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/google-chrome-stable node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js`
当前状态:
- 代码与 targeted tests 已通过,后续仅保留对 UI 复核和状态记录的收口,不再作为未完成主线。
### Worker CCommandContext FileTree 菜单 / 快捷键最小接入
Owner
- `design/01-tree-first-graph-kernel/process/1-6-next-phase-gap-closure-checklist-v1.md`
- `rust/crates/core-protocol/src/command.rs`
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`
- `scripts/task476-filetree-editor-context-menu-download-smoke.js`
- `scripts/task471-local-folder-bulk-resource-trash-smoke.js`
目标:
- 在 SSR sidebar JS 中引入最小 `CommandContext` 等价 enablement helper,先覆盖 FileTree 右键菜单和 Delete/Backspace 快捷键。
- readonly / sourceKind / selectionCount / resourceKind 的禁用语义应与 Rust `CommandContext` 测试口径一致;不要求本轮把 Rust evaluator 直接编译到 JS。
- 保持下载、多选删除、粘贴、只读阻断 smoke 不回退。
验收:
- `cargo test -p mnote-web sidebar_filetree -- --test-threads=1`
- `cargo test -p core-protocol command_context -- --test-threads=1`
- `node scripts/task471-local-folder-bulk-resource-trash-smoke.js`
- `node scripts/task476-filetree-editor-context-menu-download-smoke.js`
当前状态:
- 代码与 targeted tests 已通过,可作为 `1-6` A7 的已完成证据使用。
## 4. Codex 复核项
- [x] 逐个读取 worker 的 `final.md` / `result.json` / diffB/C 由代码 diff 与 targeted tests 复核,A 无 `final.md` / `result.json`,已记录 timeout。
- [x] 检查 worker 是否越权修改非 owner 文件:A 未采纳,B/C 改动范围与任务目标一致;Codex 对 `documents.rs` 查询兜底补了单测。
- [x] 运行各 worker 验收命令中与实际改动相关的 targeted tests。
- [x] UI/browser 可见项必须由 Codex 或浏览器测试 worker 实跑复核:`task471``task476``task451` 已有实跑记录,且 `task451` 已在最新 3000 主进程上复测通过。
- [x] 更新 `1-6``3-13`、本文执行记录:`1-6` 追认 buffer_state / task451 状态;`3-13` 追认 task486 改为当前主链 smoke 并复测通过。
- [x] 可归档的文档移动到 `done/`,不能归档的保留明确未完成项:`5-26` 已归档,`3-13` 保持 process。
- [ ] 提交前运行 `git diff --check``codegraph sync .``codegraph status`
## 5. 本轮执行记录
- 2026-05-21Codex 复核 `5-26` 最后一项,`cargo test -p mnote-web sidebar_tree_runtime_opens_office_assets_through_resource_shell -- --test-threads=1``node scripts/task463-onlyoffice-resolver-smoke.js` 通过,`5-26` 已归档。
- 2026-05-21Codex 建立 Batch E checklist,并准备派发 Worker A/B/C。
- 2026-05-21Codex 复核 `1-6``3-13` 现有 code / test 状态后,确认 `Gap A2` conflict UI 与 `Gap A7` 菜单/快捷键已落地,`Gap C1` 已完成;`Batch E` 只剩 Worker A 的 `3-13` 尾项与对文档状态的最终收口。
- 2026-05-21Reasonix Worker A 重新派发后长期未生成 `final.md` / `result.json`Codex 终止卡住的 runner / reasonix acp 进程,并记录 `.codex/reasonix-tasks/results/batch-e-worker-a-gfm-save-error-timeout.md`;后续 Codex 将 `task486` 重新对齐到当前 `/documents` 主链并复测通过,保存失败状态保留已追认。
@@ -108,13 +108,13 @@
- [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 查询
- [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 数据源改为 buffer state:前端查询 `/api/documents/buffer/state` SSE 推送 buffer 变更事件。
- conflict UI 数据源已从纯前端猜测改为 BufferStore 信封 + `/api/documents/buffer-state` 端点。后续若需要实时更新(SSE 推送 buffer 变更事件)可在此基础上扩展
---
@@ -129,8 +129,8 @@
- [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:基础设施已就绪,未接入
- [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')` 守卫。只读或无选中时阻止动作。
- [ ] 把 AI 写入能力接入 context`ai.canWrite` key 已定义,未在 hermes_tools 中消费
### 3.3 必补测试
@@ -147,12 +147,16 @@
- [x] 最小 `CommandContext` 定义 + `when` evaluator 可工作
- [x] readonly / grant / resource kind 的禁用态可测试
- [ ] **未完成**:当前 UI 中同一命令的多份 enablement 判断尚未统一
- [ ] **未完成**:菜单、按钮、快捷键可用性尚未统一
- [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` 守卫
- [ ] **未完成**:下载、多选删除、粘贴、只读阻断的 smoke 保持回退兼容
- [ ] **未完成**AI 写入能力 (`ai.canWrite`) 尚未接入 hermes_tools
### 3.5 下一步
`layout.rs` 右键菜单`hermes_tools` 的写入守卫中引入 `is_command_enabled`
- `layout.rs` 右键菜单:已引入 `evaluateSidebarFileTreeWhen`Batch C Worker C 完成)
- Delete/Backspace:已接入(Batch C Worker C 完成)
- hermes_tools 写入守卫:仍需 `ai.canWrite` 的消费
---
@@ -183,7 +183,7 @@
归档条件:
- `3-13` 三个未完成项完成后归档
- `3-13` 仅剩 `web_shell.rs` 临时适配分支移除与 process→done 迁移,`task486` 已改写到当前主链并复测通过
- `5-6` 剩余 Phase G/H 小尾项完成或拆成更小 checklist 后归档。
## 5. P2tree live cache 与 command context
@@ -365,8 +365,9 @@
当前批次状态:
- `3-13` 的空引用块、空表格单元格、legacy marks、web_shell 过渡注释已由 Batch C 追认。
- `1-6` 的 A2 浏览器可见读回、C1 export smoke 已由 Batch C 复核完成。
- `1-6` 的 A2 浏览器可见读回、conflict UI、C1 export smoke 已由 Batch C / 本轮复核完成。
- `5-26` 仍保持 process,等待最小可复核实现或新的 browser evidence。
- `task451``task486` 已在当前 3000 主进程上复测通过,不再作为本轮尾项。
### Batch Dlive cache / command context
@@ -368,7 +368,7 @@
- [x] 保留 frontmatter `title` / `mnote_id` / 页面设置写回逻辑。
- [ ] 保存失败时保留编辑器状态并给出可解释错误。
- [x] 保存失败时保留编辑器状态并给出可解释错误。
### 11.8 回归测试
@@ -429,7 +429,7 @@
| 11.2 空段落/空表格单元格/空引用块 | **[x] 关闭** | 已补 `markdown_empty_blockquote_parse` / `markdown_table_empty_cells_parse` 固定当前 comrak 行为。 |
| 11.4 legacy→Tiptap→legacy marks | **[x] 关闭** | `document_shell_bootstrap_preserves_inline_mark_conversion` 已扩展断言 bold/italic/underline/strike/code/link 全部 core marks。 |
| 11.6 列对齐/空单元格/带 mark 单元格降级策略测试 | **[ ] 部分完成** | 列对齐已追认,空单元格已补测试关闭。降级策略仍无覆盖。 |
| 11.7 保存失败状态保留 | **[ ] 保留** | 冲突/写失败返回 WebError,前端错误处理和状态保留逻辑无测试。 |
| 11.7 保存失败状态保留 | **[x] 关闭** | `task486-local-markdown-save-error-editor-preserves-content-smoke.js` 已切到当前 `/documents` 主链并复核通过,保存失败时编辑器内容与 runtime error 状态保留。 |
| 11.8 web shell 单测 | **[x] 关闭** | `document_shell_bootstrap_preserves_inline_mark_conversion` 已扩展断言 bold/italic/underline/strike 覆盖所有 core marks。 |
| 11.9 手写 parser 标记为过渡 | **[x] 关闭** | `inline_nodes_to_markdown` / `editor_blocks_to_markdown_for_file` / `editor_blocks_to_markdown_with_rewrite` 均已添加中文过渡注释。 |
| 11.9 web_shell.rs 临时适配分支移除 | **[ ] 保留** | JS 侧 `legacyStylesToTiptapMarks` 等适配函数仍存在(已加过渡注释 TODO(step-4))。 |
@@ -1,6 +1,6 @@
# 5-26 Resource Open Resolver Convergence Checklist v1
> 状态:process
> 状态:done
>
> 日期:2026-05-21
>
@@ -27,7 +27,7 @@
- [x] 审查 `buildLocalOnlyOfficeOpenUrl``openEditorAttachmentEditTab``openConvexAssetFromFileTree``resolveResourceOpen` 的重复判断。
- [x] 给出最小收敛方案:提取 `openLocalOfficeFileInActiveTab(detail, mode)` helper,收敛 `openEditorAttachmentDetail``openEditorAttachmentEditTab` 中的重复 local Office 打开分支。
- [x] 只改 `layout.rs`:新增 helper + 简化两个调用方,不改 `task463`(当前 smoke 和 Rust 单测已覆盖分流行为)。
- [ ] 补 smoke 或断言,覆盖正文附件 `弹窗编辑``新窗口编辑` 分流。
- [x] 补 smoke 或断言,覆盖正文附件 `弹窗编辑``新窗口编辑` 分流。
## 5. 验收
@@ -52,3 +52,4 @@
4. 更新测试断言为检查 `openLocalOfficeFileInActiveTab(detail, 'edit')`
5. `openConvexAssetFromFileTree` 保持不动(含 forceNewWindow/mindmap 等分支)。
- 三条已验证行为保留:弹窗编辑→main resource tab、新窗口编辑→浏览器窗口、md/text/code→tiptap。
- 2026-05-22Codex 复核 `cargo test -p mnote-web sidebar_tree_runtime_opens_office_assets_through_resource_shell -- --test-threads=1``node scripts/task463-onlyoffice-resolver-smoke.js` 通过,确认正文附件 `弹窗编辑``新窗口编辑`、FileTree 资源打开与 `/onlyoffice` 分流保持一致,`5-26` 可归档为 done。