Files
mnote/design/10-review/done/08-kernel-architecture-next-priority-review-and-checklist.md
T
lix-2026 1882db7681 收口 MNote P0 P1 P2 审查尾项
- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目
- 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线
- 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径

验证:
- cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1
- cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1
- git diff --check
- git diff --cached --check
- codegraph index . --force && codegraph status .
- codegraph sync . && codegraph status .
2026-06-01 09:29:12 +08:00

59 KiB
Raw Blame History

08 [done] Kernel 架构收口与下一阶段优先级 Review / Checklist v1

更新时间:2026-05-18

执行状态:done

关联文档:

  • /mnt/Data1T/mnote/AGENTS.md
  • /mnt/Data1T/mnote/ARCHITECTURE.md
  • /mnt/Data1T/mnote/design/01-05-current-priority-overview.md
  • /mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md
  • /mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md
  • /mnt/Data1T/mnote/design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md
  • /mnt/Data1T/mnote/design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md
  • /mnt/Data1T/mnote/design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md
  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md
  • /mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md

2026-06-01 口径补充:本文是 2026-05-18 的历史 review / checklist 快照。文中把 mnote.doc.markdown_edit 描述为简单正文编辑主路径的结论已被后续 local-first agent 文件编辑控制面覆盖;当前 local-first 普通 Markdown 编辑主路径以 AGENTS.mdARCHITECTURE.mddesign/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md 为准。mnote.doc.markdown_edit 只保留为 remote/cloud/compat fallback 或结构校验辅助。


1. Review 结论

当前内核架构的骨架已经基本成立,但还不能说“已完善”。

已经成立的部分:

  • tree-first graph kernel 是长期语义事实源。
  • mnote-web 已是 3000 主 Web 执行面。
  • 文档页默认主编辑器已切到页面内 leptos-tiptap island。
  • Page Aggregate 已进入 Rust-first 读取链,并已输出 blockDocument / blockProjectionVersion / projectionSource
  • 页面/块 AI tools 已开始走 mnote.doc.* / mnote.block.*、Page Aggregate block projection 和 Rust EditorCommand

仍未完善的部分:

  • Page Aggregate 仍是过渡态,block projection 主要从 documents.content / local markdown content 投影,不是 EditorBlockDocument 原生落库完成态。
  • 标题、正文、页面设置、page tree、AI 写入口尚未完全闭环到同一组 projection / command family。
  • tree.* 已是 preferred command name,但 documents.* 兼容命令面仍未完全降级。
  • /api/realtime/ws 已是 tree realtime 主链,/api/tree/events 已降级为 SSE fallbacklive cache 的后续重点是减少兼容 fallback 与补偿链。
  • AI 块工具已有最小闭环,但当前编辑路径以块操作(blockId)为中心——AI 被迫理解 UI 层概念,且本地 .md 文件无 AI 写入路径。7-14 提出应将 AI 编辑主路径修正为 markdown 文本级(search/replace),mnote.block.* 降级为结构性辅助,在线 Convex 文档与本地文件共用同一条 markdown 写入路径。

补充 BlockNote / Tiptap AI 参考后的判断:

  • BlockNote AI 和 Tiptap AI Toolkit 可以参考的是 AI runtime shape 与 tool contract,不是 mnote 的事实源。
  • AI 方向下一步只应补基础底座:PageAIContextBuilderscope=selectionpage_xml/text、tool manifest annotations、PageAIReviewSession、accept/reject/retry/abort 状态机。
  • 2026-05-18 补充(7-187-25 收口后):AI 简单正文编辑主路径已切到 markdown 文本级 search/replace / full_contentpage_ai_workflow.rs 当前通过模型生成 markdown 编辑意图后调用 mnote.doc.markdown_edit,并复用统一 mnote tool executorlocal_rule plannerdirect_block_edit_operations)不再作为当前 runtime 口径。在线 Convex 文档和本地 .md 文件共用同一条 markdown 写入合同。
  • 在非 AI 主架构和 AI 基础合同打牢之前,不应扩展新的 AI agent 工作流、复杂 AI UI 或跨页面智能功能。

因此,下一阶段不应优先“大改架构”或“大量加新功能”,而应优先做:

架构收口 + 验收矩阵 + 定向找 bug。

更具体地说:

先打牢除 AI 以外的 Page Aggregate / tree command / tree realtime 主架构,再把 AI 的基础读写、上下文、冲突与审阅底座打牢;之后才进入 AI 功能扩展。


2. 下一步总优先级

总原则:

  • 非 AI 主架构优先级高于 AI 功能扩展。
  • AI 当前只推进基础设施,不推进新功能面。
  • AI 基础设施必须服从 Rust kernel / Page Aggregate / EditorCommand / Hermes audit,不引入 BlockNote runtime 或 Tiptap/ProseMirror editor truth。

P0Page Aggregate 单一真源收口

目标:

  • 标题、正文、页面设置、page tree、AI 读写入口继续收敛到同一组 Page Aggregate projection / command family。
  • 前端不在页面壳、island 外侧、Sidebar preferred snapshot 外再拼第二份页面真相。
  • 明确当前 block projection 过渡态和长期 EditorBlockDocument 原生落库目标之间的边界。

判断标准:

  • 页面读取只走 Rust /api/page-aggregate/:id 正式读链。
  • 页面标题、正文、页面设置写入后,Page Aggregate、页头、Sidebar、Breadcrumb、File Tree、AI fetch 回读一致。
  • 失败时明确 degraded / conflict / stale,不返回看似成功的旧快照。

P0Tree Command Cutover

目标:

  • tree.* 成为正式命令面。
  • documents.* 只保留为兼容层,不再继续扩写长期业务语义。
  • 页面新建、重命名、移动、归档、恢复、删除、资源生命周期都能通过正式 tree/page command 解释。

P0Tree Realtime Live Cache 统一

目标:

  • /api/realtime/ws 的 snapshot / delta / resync 成为 Sidebar、Page Tree、File Tree、page subtree 的共同 live cache 来源,/api/tree/events 仅作为 SSE fallback。
  • 减少 query/refetch/freshness 补偿链和旧快照回闪。

P0AI 基础工具与审阅底座

目标:

  • 不继续扩新 AI 功能,先把当前 mnote.doc.* / mnote.block.* 变成可靠、可测、可审阅、可回滚的基础工具链。
  • 参考 BlockNote / Tiptap 的架构形态,但保持 mnote Rust-owned tool runtime。

必须补齐:

  • PageAIContextBuilderscope=selection
  • format=page_xml/text/json 的稳定输出边界。
  • tool manifest annotationsreadonly/destructive/requiresApproval/selectionEffect/runtimeOwner/writeOwner
  • PageAIReviewSessionpreview -> accept/reject/retry/abort。
  • 多块插入的边界与 inserted block ids。
  • 复杂块移动阻断矩阵。
  • stale revision / stale blockRevisionRef / idempotency 重放。

明确不做:

  • 不新增跨页面 AI agent 工作流。
  • 不新增复杂 AI 自动化功能面。
  • 不把 @blocknote/xl-ai 或 BlockNote AIExtension 作为 runtime dependency。
  • 不让 AI 写入绕过 dryRun/idempotencyKey/revision/conflictDetectionKey/revisionRef
  • 不把 direct_block_edit_operations / local_rule planner 当作当前或长期 AI 编辑路径;简单正文编辑当前主路径是 mnote.doc.markdown_edit,结构性块操作才使用 apply_block_ops / mnote.block.*
  • 不新增 mnote.block.* 工具;现有保留为结构性辅助。

2026-05-18 状态更新(7-187-25 收口后):

  • Phase A / B 主路径已完成当前收口mnote.doc.markdown_edit + mnote.doc.fetch 增强、Hermes manifest / guidance、page_ai_workflow.rsmarkdown_edit、统一 mnote tool executor、local / online markdown source 合同已同步。
  • Phase C 仍冻结:流式 apply + suggest/review 只保留设计边界,当前不实施、不扩新 AI 功能。
  • 在线 Convex 文档和本地 .md 文件共用同一条 markdown AI 写入路径(resolve_source → Convex | LocalFS)。

P1:定向 Bug Hunt

目标:

  • 不做泛泛“找 bug”,只围绕已知架构风险做定向排查。

优先找:

  • Page Aggregate 回流不一致。
  • AI 块写入 conflict / stale revision。
  • File Tree {title}.md 与 page title sync。
  • tree stream resync / 双浏览器一致性。
  • debug / compat / fallback 是否混入主链。

3. 可执行 Checklist

3.1 Page Aggregate 单一真源

  • 盘点历史 wolai-frontend/src/lib/documents/page-aggregate-loader.ts 是否仍有 runtime fallback 或 TS builder 读取分支。
  • 盘点历史 wolai-frontend/src/lib/documents/page-aggregate-builder* 的引用,确认只剩 test helper / historical adapter。
  • 检查 /api/documents/page 仍返回明确 410,不参与 runtime 主链。
  • 跑文档页打开 smoke,记录 /api/page-aggregate/:id 是首要读链。
  • 新建页面后检查 Page Aggregate identity/head/body/tree/stats 字段完整。
  • 修改标题后检查 Page Aggregate、页头、Breadcrumb、Sidebar、File Tree {title}.md 同步。
  • 修改正文后检查 Page Aggregate body.revision/conflictDetectionKey/blockDocument 同步。
  • 修改页面设置后检查 Page Aggregate 与 island runtime page options 同步。
  • 刷新页面后检查标题、正文、页面设置不回退到旧快照。
  • 破坏或暂停 Convex query,检查响应是 degraded/error,不返回伪 fixture。
  • design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md 勾选已验证项,并补证据路径。

2026-05-16 静态审计证据(历史 Next 前端退役前快照):

  • wolai-frontend/src/lib/documents/page-aggregate-loader.ts 只通过 loadPageAggregateFromRustSnapshot 请求 Rust /api/page-aggregate/:documentIdloadPageAggregate 不再回退 TS builderbuildServerBridgeRequest("/documents/page") 只用于构造转发 header/request,不调用 Next /api/documents/page compat route。
  • rg -n "buildPageAggregateFromDocumentPayloads|page-aggregate-builder" wolai-frontend/src rust scripts design --glob '!design/05-editor-mainline/reference-code/**' --glob '!node_modules/**' 显示 runtime 非测试引用仅剩 builder 定义;代码引用只有 wolai-frontend/src/lib/documents/page-aggregate-builder.test.ts
  • wolai-frontend/src/app/api/documents/page/route.ts 明确返回 410,错误文案指向 /api/page-aggregate/:documentIdroute.test.ts 覆盖该行为。
  • 已通过:cargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregatecargo test --manifest-path rust/Cargo.toml -p bridge-runtime page_aggregatecd wolai-frontend && pnpm test src/app/api/documents/page/route.test.ts src/lib/documents/page-aggregate-builder.test.ts
  • 全仓 git diff --check 当前被既有删除文件 rust/spikes/leptos-tiptap-spike/trunk-8123.err 阻断:fatal: unable to generate checkdiff for ...;本轮未清理该无关脏改动,已改用限定文件 diff check 复核。

2026-05-16 真实 3000 smoke 证据:

  • MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task110-page-title-single-truth-smoke.js 通过,证据:tmp/page-aggregate-single-truth-smoke/20260516-182244/task110.stdout.json。该脚本创建两页、修改标题,并验证页头、Breadcrumb、Sidebar、Page Tree、File Tree 与刷新后标题一致。
  • 文档页打开与 Page Aggregate snapshot 验证通过,证据:tmp/page-aggregate-single-truth-smoke/20260516-182244/page-open-snapshot.stdout.json,截图:tmp/page-aggregate-single-truth-smoke/20260516-182244/page-open-snapshot.png。文档响应 x-mnote-web-owner=mnote-webx-mnote-web-shell=documentHTML 包含 data-page-aggregate-snapshot="mnote.page_aggregate.v1"data-page-tree-source="page_aggregate.tree.pageSubtree",同一临时页 /api/page-aggregate/:id 回读 schema=mnote.page_aggregate.v1
  • 新建页面 Page Aggregate 字段完整性验证通过,证据:tmp/page-aggregate-single-truth-smoke/20260516-182244/page-aggregate-fields.stdout.jsonidentity/head/body/tree/stats 全部为 truebody.blockProjectionVersion=1projectionSource=documents.content
  • 说明:曾尝试在浏览器 network 中直接捕获 /api/page-aggregate/:id,证据 page-open-network.stderr.log;当前 Rust SSR 主入口会直接把 Page Aggregate snapshot 写入 HTML,浏览器侧不必出现该 API 请求,因此该尝试不作为失败验收项。

2026-05-16 正文写入后 body 同步证据:

  • 新增并运行 scripts/task-page-aggregate-body-sync-smoke.js,通过真实 3000 文档页输入正文,等待 /api/documents/save 成功后轮询 /api/page-aggregate/:id
  • 证据:tmp/page-aggregate-body-sync-smoke/mp87mgz7.json,截图:tmp/page-aggregate-body-sync-smoke/mp87mgz7.pngstdouttmp/page-aggregate-body-sync-smoke/latest.stdout.json
  • 验证结果:body.revision0 更新到 1body.conflictDetectionKeytree_1778927703753_1:0 更新到 tree_1778927703753_1:1body.blockProjectionVersion=1projectionSource=documents.contentblockDocument.blocks[0] 回读到文本 Page Aggregate body sync mp87mgz7revisionRef=pageRev:1:block:block_1:hash:fnv1a64:208e0e63c853eef5
  • 配套测试已通过:cargo test --manifest-path rust/Cargo.toml -p mnote-web documents_save_route_executes_page_body_save_commandcargo test --manifest-path rust/Cargo.toml -p bridge-runtime page_aggregate_get_projects_legacy_content_to_block_document

2026-05-16 页面设置写入后 pageOptions 同步证据:

  • 新增并运行 scripts/task-page-aggregate-options-sync-smoke.js,通过真实 3000 文档页打开页面设置,依次修改 wideLayout=truesmallText=truelayoutDensity=compact,等待 /api/documents/options 返回 page.layout.updateOptions 后轮询 /api/page-aggregate/:id
  • 证据:tmp/page-aggregate-options-sync-smoke/mp87y6j3.json,截图:tmp/page-aggregate-options-sync-smoke/mp87y6j3.pngstdouttmp/page-aggregate-options-sync-smoke/latest.stdout.json
  • 验证结果:Page Aggregate layout.pageOptions 依次回读到 wideLayout=truesmallText=truelayoutDensity=compact;运行时 DOM 同步为 data-page-wide-layout="true"data-page-small-text="true"data-layout-density="compact"island editorRoot.editor-surface 同步,字号从 16px15px,段落间距从 8px4px
  • 配套测试已通过:cargo test --manifest-path rust/Cargo.toml -p mnote-web documents_options_route_executes_page_layout_update_optionscd wolai-frontend && pnpm test src/lib/documents/page-command-client.test.ts src/components/editor/leptos-tiptap-island-editor-host.test.tsx src/lib/documents/page-option-semantics.test.ts

2026-05-16 刷新后标题 / 正文 / 页面设置不回退证据:

  • 新增并运行 scripts/task-page-aggregate-refresh-persistence-smoke.js,同一临时页内依次通过 UI 写入标题、正文和页面设置,等待 Page Aggregate 回读最新 head/body/layout 后刷新页面,再断言页头、正文 DOM、页面设置控件、runtime DOM 与 /api/page-aggregate/:id 均保持最新值。
  • 证据:tmp/page-aggregate-refresh-persistence-smoke/mp88fr6k.json,截图:tmp/page-aggregate-refresh-persistence-smoke/mp88fr6k.pngstdouttmp/page-aggregate-refresh-persistence-smoke/latest.stdout.json
  • 验证结果:刷新前后 head.title=Page Aggregate refresh mp88fr6kbody.revision=1body.conflictDetectionKey=tree_1778929070007_1:1blockDocument.blocks[0].text=Page Aggregate refresh body mp88fr6klayout.pageOptions.wideLayout/smallText/layoutDensity=true/true/compact;刷新后页头标题、.ProseMirror 正文、设置控件、documentElement.document-shell、island root 和 .editor-surface 均保持最新值。
  • 修复点:rust/crates/mnote-web/src/ssr/pages/layout.rsinitializePageUiSurfaces 延后到 DOMContentLoaded 后执行,避免 layout 脚本早于嵌入 Page Aggregate JSON / island DOM 完成时把 runtime 属性按默认 pageOptions 应用。
  • 2026-05-18 复测并扩展 scripts/task-page-aggregate-refresh-persistence-smoke.js,补充 mnote.doc.fetch / tree.pageSubtree 同组回读证据。证据:tmp/page-aggregate-refresh-persistence-smoke/mpagfma1.json,截图:tmp/page-aggregate-refresh-persistence-smoke/mpagfma1.png
  • 验证结果:刷新前后 head.title=Page Aggregate refresh mpagfma1body.revision=1body.conflictDetectionKey=tree_1779063433221_1:1blockDocument.blocks[0].text=Page Aggregate refresh body mpagfma1layout.pageOptions.wideLayout/smallText/layoutDensity=true/true/compacttree.pageSubtree.rootNodeId=tree_1779063433221_1 均一致;mnote.doc.fetch 返回 schema=mnote.page_ai_context.v1revision/conflictDetectionKey/revisionRef/text 与同一 Page Aggregate block 完全一致。
  • 缺陷记录:bugs/05-editor-mainline/done/5-12-page-options-refresh-runtime-attrs-v1.md
  • 配套测试已通过:cargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregatecargo test --manifest-path rust/Cargo.toml -p mnote-web documents_options_route_executes_page_layout_update_options

2026-05-16 Convex query 失败时不返回伪 fixture 证据:

  • rust/crates/mnote-web/src/routes/web_shell.rs 补充负向 route 测试,构造隔离配置 convex_url=http://127.0.0.1:9allow_dev_fixtures=falsequery_fixtures_json=None,模拟 Convex query 不可达。
  • /api/page-aggregate/doc_1?workspaceId=ws_demo 返回 503 SERVICE_UNAVAILABLEx-error-code=convex_unavailablex-error-phase=query_sendx-upstream-service=convexbody 为 ok=false/code=convex_unavailable,且没有 schema / result
  • /documents/doc_1?workspaceId=ws_demo 返回同类错误 JSONHTML body 不包含 mnote.page_aggregate.v1data-mnote-dev-fixturedata-page-aggregate-snapshot
  • 验证命令已通过:cargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregate_endpoint_errors_without_convex_or_fixture -- --nocapturecargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_errors_without_convex_or_fixture -- --nocapturecargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregate

验证命令建议:

cargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregate
cargo test --manifest-path rust/Cargo.toml -p bridge-runtime page_aggregate
node scripts/task110-page-title-single-truth-smoke.js
node scripts/task-page-aggregate-body-sync-smoke.js
node scripts/task-page-aggregate-options-sync-smoke.js
node scripts/task-page-aggregate-refresh-persistence-smoke.js
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_aggregate_endpoint_errors_without_convex_or_fixture
cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_errors_without_convex_or_fixture

3.2 Page Block AI Tooling

  • 7-10 为工具执行清单、7-12 为当前 AI runtime 基础设计,逐 phase 检查已勾选项是否都有代码、测试、smoke 证据。
  • mnote.doc.fetch scope=selection 补真实选区上下文输入和返回结构。
  • mnote.doc.fetch format=page_xml 补最小 PageXML 输出。
  • mnote.block.fetch format=text/page_xml 补格式分支。
  • 给 tool manifest 补 annotations,区分 readonly / destructive / requiresApproval / selectionEffect。
  • 定义 mnote.page_ai_context.v1,明确 context 只来自 Page Aggregate projection。
  • 定义 mnote.page_ai_review_session.v1,明确 accept / reject / retry / abort 语义。
  • mnote.block.insert_after 补多块插入限制和返回 inserted block ids。
  • mnote.block.move_after 补标题带子块阻断 smoke。
  • mnote.block.move_after 补列表项阻断 smoke。
  • mnote.block.move_after 补表格 / mindmap / resource 阻断 smoke。
  • mnote.block.replace 补 stale revision 失败用例。
  • mnote.block.replace 补 stale blockRevisionRef 失败用例。
  • 给写工具补重复 idempotencyKey 的端到端用例。
  • 检查 mnote.page.save 在 manifest / UI 中继续标为页面级兜底,不显示为精确块编辑主入口。
  • 检查任何新增 AI surface 是否只是基础 review/context/tooling 验收,不是新功能扩展。
  • 更新 design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md 的每个 phase 证据。
  • 更新 design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md 的 Hermes 工具路由与审阅面 checklist。

2026-05-18 mnote.block.insert_after 多块插入证据:

  • 代码:rust/crates/mnote-web/src/hermes_tools/block.rs 支持 content / block / blocks 输入;blocks 限制 1..=20;多块写入按输入顺序连续插入,并在结果返回 insertedBlockIds
  • manifestrust/crates/mnote-web/src/hermes_tools/manifest.rs 已声明 blocks.minItems=1/maxItems=20,并用 anyOf 表达 content | block | blocks 三种输入。
  • 测试:cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_insert_after -- --nocapture 通过,覆盖多块成功和超过 20 个失败。
  • 回归:cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture 通过,覆盖 Hermes tools 38 项。

2026-05-18 mnote.block.move_after 复杂块阻断证据:

  • 代码:rust/crates/mnote-web/src/hermes_tools/block.rs 继续以同父级、叶子块、可移动类型、editable、自身移动为真实写入前阻断条件。
  • 测试:cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_block_move_after_blocks_complex_and_nested_blocks -- --nocapture 通过,覆盖标题带子块、列表项、表格、mindmap、resource 均返回 blocked=true / block_move_after_blocked
  • 回归:cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture 通过,当前 Hermes tools 共 39 项。

新增(2026-05-187-187-25 收口状态):

Phase A / B(当前主路径已收口):

  • mnote.doc.markdown_edit 核心实现:resolve_source → search_replace / full_content → write_target
  • mnote.doc.markdown_edit 搜索替换语义:精确匹配、归一化匹配、多操作同块合并、无法安全映射时失败
  • mnote.doc.markdown_edit Convex 在线写入 adapter 以最终 markdown 映射写回
  • mnote.doc.markdown_edit 本地文件写入 adapter 尊重 dryRun / idempotency
  • mnote.doc.fetch format: "markdown" 增强
  • Hermes tool manifest 注册并描述 mnote.doc.markdown_edit 写入合同
  • 乐观锁:revision / conflictDetectionKey 前置校验
  • direct_block_edit_operations / local_rule 不再作为 page_ai_workflow.rs 当前主路径
  • page_ai_workflow.rs 改为模型产 markdown search/replace / full_content,底层走 mnote.doc.markdown_edit
  • 单元测试覆盖 markdown_edit / page_ai_workflow / Hermes guidance / ACP tool contract

Phase C(设计冻结,不实施):

  • 流式 apply + suggest/review 设计已冻结,不阻塞 Phase A/B 实施

2026-05-18 Review Session 合同定义:

  • 已在 design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md 定义 mnote.page_ai_review_session.v1 最小 schema。
  • 已明确状态:draft/planning/previewing/awaiting_user/accepted/rejected/applying/applied/failed/aborted/stale
  • 已明确动作约束:accept 必须重新读 Page Aggregate 并校验 revision / conflictDetectionKey / revisionRefreject/abort 不产生写入,retry 必须生成新 proposal 或 dry-run previewyolo 模式也应生成同构 audit 数据。
  • 边界:这里只完成合同定义,不实施 Phase C 流式 apply 或新的审阅 UI。

2026-05-16 Page Block AI context / format focused smoke 证据:

  • 新增并运行 scripts/task-page-block-ai-context-format-smoke.js,通过真实 3000 + 测试账号创建临时页,用 mnote.page.save 初始化 p_1/p_2/p_3,再验证 Hermes mnote tools 的 context / format / annotations / selection guard。
  • 证据:tmp/page-block-ai-context-format-smoke/mp8ddr4n.json,截图:tmp/page-block-ai-context-format-smoke/mp8ddr4n-page.png
  • 验证结果:
    • GET /api/hermes/tools/mnote/manifestmnote.doc.fetchmnote.block.fetchmnote.block.replacemnote.page.save 均包含 readonly/destructive/idempotent/requiresApproval/approvalMode/runtimeOwner/writeOwner/selectionEffectmnote.page.save 明确 destructive=trueapprovalMode=yolo,继续定位为页面级粗粒度兜底。
    • mnote.doc.fetch scope=selection selectedBlockIds=["p_2"] format=page_xml 返回 schema=mnote.page_ai_context.v1allowedTargetBlockIds=["p_2"]revision/conflictDetectionKeyrevisionRefcontent 只包含 p_2第二段 mp8ddr4n,不包含未选中的 p_1/p_3
    • mnote.doc.fetch scope=selection format=text 返回 [p_2] 第二段 mp8ddr4n,不包含未选中块。
    • mnote.block.fetch blockId=p_2 format=page_xml/text 返回目标块、revisionRef 和同父级 before/after 上下文 p_1/p_3
    • mnote.doc.apply_block_ops dryRun=true allowedTargetBlockIds=["p_2"] 尝试 replace p_1 被拒绝,HTTP 400,错误码 mnote_block_target_out_of_scope
  • 边界:本轮只验证 mnote.doc.apply_block_ops 的 selection scope guard;单个 mnote.block.replace/insert_after/move_after 尚未校验 allowedTargetBlockIds,不能据此勾选完整 selection 写保护矩阵。
  • 配套验证已通过:node --check scripts/task-page-block-ai-context-format-smoke.jscargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocaptureMNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-context-format-smoke.js

2026-05-16 / 2026-05-18 Page Block AI stale / idempotency focused smoke 证据:

  • 新增并运行 scripts/task-page-block-ai-conflict-idempotency-smoke.js,通过真实 3000 + 测试账号创建临时页,用 mnote.page.save 初始化 p_1/p_2,再围绕 mnote.block.replace 验证冲突和幂等安全边界。
  • 证据:tmp/page-block-ai-conflict-idempotency-smoke/mp8dyqiq.json,截图:tmp/page-block-ai-conflict-idempotency-smoke/mp8dyqiq-page.png
  • 最新复测证据:tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs.json,截图:tmp/page-block-ai-conflict-idempotency-smoke/mpafrevs-page.png
  • 验证结果:
    • 首次 mnote.block.replace 携带最新 revision/conflictDetectionKey/blockRevisionRef/idempotencyKey 成功写入 p_2,返回 commandName=page.body.savecommandId=page_body_save_req_1778938353824_11
    • 使用同一 idempotencyKey=idem_conflict_replace_mp8dyqiq 再次调用 mnote.block.replace,即使请求 content 改成不同文本,也 replay 同一 commandIdPage Aggregate 回读 p_2 仍为首次写入文本,revisionAfterFirst=2revisionAfterReplay=2,确认不重复写入。
    • 使用旧 revision/conflictDetectionKey 调用 mnote.block.replace 返回 HTTP 400、错误码 mnote_tool_conflict,正文保持首次写入结果。
    • 使用最新 revision/conflictDetectionKey 但旧 blockRevisionRef 调用 mnote.block.replace 返回 HTTP 400、错误码 mnote_tool_conflict,正文保持首次写入结果。
    • 2026-05-18 复测中,重复 idempotencyKey=idem_conflict_replace_mpafrevs replay 同一 commandId=page_body_save_req_1779062303997_525revisionAfterFirst=2revisionAfterReplay=2;旧 revision 与旧 blockRevisionRef 仍均返回 mnote_tool_conflict
  • 边界:本轮只覆盖 mnote.block.replace 直接 tool executor 的 stale revision / stale blockRevisionRef / idempotency replay;不代表 mnote.block.insert_after 幂等矩阵、所有写工具幂等矩阵、review session accept stale 或 accept/reject/retry/abort 已完成。
  • 配套验证已通过:node --check scripts/task-page-block-ai-conflict-idempotency-smoke.jscargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocaptureMNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-conflict-idempotency-smoke.js

验证命令建议:

cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools
cargo test --manifest-path rust/Cargo.toml -p bridge-runtime editor_document
node scripts/task-page-block-ai-tools-smoke.js

3.3 Tree Command Cutover

  • rg -n "documents\\.create|documents\\.title\\.update|documents\\.move|documents\\.archive|documents\\.restore" rust wolai-frontend 盘点旧命令引用。
  • 将仍在 runtime 主链的旧命令按 owner 分类:必须迁移、兼容保留、测试 fixture。
  • 确认页面新建默认输出 tree.node.create 或正式 tree command。
  • 确认页面重命名默认输出 tree.node.rename 或正式 page/tree command。
  • 确认移动页面默认输出 tree.subtree.move
  • 确认归档 / 恢复 / 永久删除的 command family 与 resource lifecycle 设计一致。
  • 对 compat alias 返回增加 owner / deprecated 标识,避免被当作主链。
  • 更新 design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md 或新增后续 process checklist。

2026-05-18 当前 Tree Command Cutover 状态:

  • 3000 当前主壳由 Rust mnote-web SSR 承载;主要页面生命周期动作通过 Rust /api/tree/commands route 生成 tree.node.createtree.node.renametree.subtree.movetree.node.archivetree.node.restoretree.node.purgetree.subtree.copy
  • bridge-runtime 仍接受历史 documents.* alias,但 execution plan / artifact 会标记 preferredCommandNamecompatCommandNamedeprecatedAlias,避免兼容命令被当成当前主链。
  • wolai-frontend / Next tree command route 只作为退役前历史审计材料,不再作为当前运行时主链依据。

2026-05-16 Tree Command Cutover 静态盘点与 alias 标识证据(历史 Next 前端退役前快照):

  • 只读盘点命令:rg -n "documents\\.(create|title\\.update|move|archive|restore|delete|purge|copy_tree)" rust wolai-frontend scripts --glob '!node_modules/**'
  • 退役前 Next 前端主链:wolai-frontend/src/lib/documents/tree-command-client.ts 的新建、重命名、移动、归档、恢复、永久删除和复制均 POST /api/tree/commands,返回 meta 使用 TREE_COMMAND_PROTOCOL.*.preferredCommandNameTREE_COMMAND_PROTOCOL 中的 documents.* 只保留为 compatCommandName
  • 退役前 Next tree command routewolai-frontend/src/app/api/tree/commands/route.ts 在 create / move / rename / archive / restore 分支分别构造 tree.node.createtree.subtree.movetree.node.renametree.node.archivetree.node.restore
  • Rust Web tree routerust/crates/mnote-web/src/routes/tree.rscreate_command_wire 输出 tree.node.createtree.node.renametree.subtree.movetree.node.archivetree.node.restoretree.node.purgetree.subtree.copytree_command route 只接收 action,不接收旧 documents.* command name 作为主链输入。
  • 兼容保留:bridge-runtime 仍接受 documents.create/title.update/move/delete/restore/purge/copy_tree,但本轮已在对应 execution plan 的 args_json.commandProtocol 增加 family=treeowner=rust-runtime-kernelpreferredCommandNamecompatCommandNamedeprecatedAlias;旧 documents.* alias 会标记 deprecatedAlias=true
  • Transport 边界:rust/crates/mnote-web/src/transport/convex.rs 发送给 Convex legacy mutation 前会剥离 commandProtocolstreamDeltaHintdomainEventHintdomainEventPlan(s),避免 legacy validator 把审计字段当写入参数。
  • 仍保留为后续兼容收口点:wolai-frontend/src/app/api/documents/create-child/route.ts / page-command-adapter.ts 仍构造 documents.create,当前分类为 compat-onlymnote-cli 仍有历史 documents.* CLI 构造,不属于 3000 主交互链。

2026-05-16 Tree Command Cutover 验证命令:

cargo test --manifest-path rust/Cargo.toml -p bridge-runtime tree_ -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web convex_command_args_strips_tree_archive_artifacts_for_legacy_mutation -- --nocapture

验证命令建议:

cargo test --manifest-path rust/Cargo.toml -p bridge-runtime tree_command
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command
node scripts/task122-rust-web-create-page-ui-smoke.js

3.4 Tree Realtime Live Cache

  • 2026-05-17 WS push 迁移(57ec8322):/api/realtime/ws 成为主 transportSSE 降级为 fallback。mutation 后通过 stream_delta_tx broadcast channel 推送 deltaWS 客户端零 Convex 查询。
  • 盘点 Sidebar、Page Tree、File Tree、page subtree 仍依赖 query/refetch/freshness 补偿的位置。
  • 确认 /api/realtime/ws(主)和 /api/tree/events SSE fallback 的 snapshot / delta / resync payload 覆盖 page/file/resource row。
  • 新建页面后,双浏览器 A/B 检查另一端无需刷新出现页面。
  • 重命名页面后,双浏览器 A/B 检查 Sidebar / Breadcrumb / File Tree 一致更新。
  • 移动页面后,双浏览器 A/B 检查 tree order 不回闪。
  • 删除 / 恢复后检查 trash 与主树事件一致。
  • 断开 WS / SSE fallback 后恢复,检查 resync 能把 UI 拉回正确状态。
  • 更新 design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md 的已验证项。

2026-05-18 当前状态更新:

  • /api/realtime/ws 已成为 Rust SSR 主壳默认 transportconvex-command-log-ws),/api/tree/events 仅作为 SSE fallback。
  • CURRENT_ARCHITECTURE.mdbugs/03-rust-web/done/3-163-18 已同步:原“WS 文档口径 / 前端 SSE 实现”冲突、SSE push 跳过 polling safety net、WS/SSE delta 合同分裂均已修复。
  • 2026-05-16 下面的 SSE smoke 证据保留为迁移前历史验证材料,不再代表当前主链。

2026-05-16 Tree Realtime Live Cache 静态盘点与 payload 覆盖证据(WS 迁移前历史快照):

  • 退役前只读审查确认 React AppLayoutShell 同时接入 useSidebarDatauseSidebarTreeStreamusePreferredSidebarSnapshot 负责 freshness 仲裁;Page Tree / File Tree 通过 preferred snapshot 消费 kernelSidebarTreekernelFileTreeProjection
  • 退役前未统一的补偿链:useSidebarData 还保留 Convex query、HTTP /api/sidebar fallback 与手动 refetchmutation 后仍有 refreshTree / sidebarQuery.refetchRust SSR shell 与 React hook 当时各自可建立 EventSourcepage subtree 当时仍从 Page Aggregate client state 派生。
  • Rust stream 历史盘点确认 workspace snapshot 已同时加载 KernelProjectionKind::SidebarTreeKernelProjectionKind::FileTreeSSE payload 的 data.dataset.kernel_sidebar_projection / data.dataset.kernel_file_tree_projection 覆盖 page/file rowsubtree snapshot 当时只覆盖 page_tree,不含 file tree projection。
  • 本轮新增 stream_change_preserves_remove_asset_delta_fields,确认 tree.resource.deleteremove_asset delta 字段保真;structural_delta_requires_projection_snapshot 已覆盖 remove_asset 需要 projection snapshot,避免资源删除类事件只靠局部 patch。
  • 本轮强化 scripts/task123-rust-web-tree-live-stream-consumer-smoke.js:解析 SSE snapshot data,断言 kind=snapshotstream=workspaceprojection=sidebar_treex-mnote-tree-stream-owner=rust-web,并确认 workspace snapshot 中有 kernel_sidebar_projectionkernel_file_tree_projection 和临时页 doc:<documentId> file tree row。

2026-05-16 Tree Realtime Live Cache 验证命令:

cargo test --manifest-path rust/Cargo.toml -p mnote-web stream_change_preserves_remove_asset_delta_fields -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web structural_delta_requires_projection_snapshot -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web routes::stream_support -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_events -- --nocapture
cd wolai-frontend && pnpm test src/components/sidebar/use-preferred-sidebar-snapshot.test.tsx src/lib/tree-stream/use-sidebar-tree-stream.test.tsx
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js

3000 smoke 证据:

  • tmp/tree-live-cache-smoke/20260516-task123/task123.stdout.json,结果 owner=rust-webstream=/api/tree/eventssnapshotProjection=sidebar_treefileTreeRows=59

2026-05-16 双浏览器 no-refresh 验证与 purge 修复证据:

  • 复用 scripts/task432-filetree-trash-page-dual-browser-no-refresh-smoke.js 做真实 3000 双浏览器验证:A 端通过真实 auth + /api/tree/commands 创建页面、归档、恢复、彻底删除与清空垃圾箱;B 端同时打开 File Tree 与 Trash,断言目标行无刷新出现 / 消失,且 navigationEvents 在初始打开后为空。
  • 修复前该 smoke 在 purge-visible-on-b 前失败:documents:purge 收到 artifact-only 字段 commandProtocolConvex legacy validator 返回 ArgumentValidationError: Object contains extra field commandProtocol
  • 修复点:rust/crates/mnote-web/src/transport/convex.rstree.node.purge / documents.purge 加入 strip_tree_artifact_fields 剥离范围,避免 compat mutation 接收 tree command audit 字段。
  • 缺陷记录:bugs/04-tree-domain/done/4-41-tree-node-purge-command-protocol-leaks-to-convex-v1.md
  • 修复后 task432 通过,证据 tmp/tree-live-cache-smoke/20260516-task432/result.jsonok=truecreate-visible-on-b 通过 tree:resync 出现在 B 端 File Treearchive-visible-on-b 通过 tree:delta remove_document 同步 File Tree 与 Trashrestore-visible-on-b 通过 tree:delta upsert_document 同步恢复;purge-visible-on-bempty-trash-visible-on-b 通过 tree:resync 拉回正确状态。

2026-05-16 purge 修复验证命令:

cargo test --manifest-path rust/Cargo.toml -p mnote-web convex_command_args_strips_tree_purge_artifacts_for_legacy_mutation -- --nocapture
cargo test --manifest-path rust/Cargo.toml -p mnote-web convex_command_args_strips_tree_archive_artifacts_for_legacy_mutation -- --nocapture
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task432-filetree-trash-page-dual-browser-no-refresh-smoke.js

2026-05-16 双浏览器 rename live cache 修复与验证记录:

  • 新增 regression smokescripts/task446-tree-rename-dual-browser-live-smoke.js。脚本使用 A/B 独立 browser contextA 端通过正式 /api/tree/commands 创建并执行 { action: "rename", workspaceId, documentId, title },B 端分别保持目标文档页与 File Tree 页面不刷新,记录 tree:snapshot/tree:delta/tree:resync/api/tree/events 请求、DOM 状态、导航事件与截图路径。
  • RED 证据:修复前真实 3000 smoke 失败,B 端已收到 tree:deltaop=upsert_documentliveApplied=deltaliveError=""Sidebar / Page Tree 与 File Tree {renamedTitle}.md 已更新,但当前打开目标文档页的 titleInputValue、Breadcrumb 与 document.title 仍停留旧标题,导致 waitForBDocumentRename 超时。
  • 根因:Rust SSR 文档 shell 的 updateTitleEverywhere 已更新 Page Tree / File Tree 行标题,但 title-only upsert_document 未同步当前文档页 chrome(页头标题输入框、Breadcrumb、document.title)。
  • 修复点:rust/crates/mnote-web/src/ssr/pages/layout.rsupdateTitleEverywhere(documentId, title) 现在同步当前文档 chrome,并保持 scoped tree row 更新;字符串合同单测新增当前页 title input 与 Breadcrumb selector 覆盖。
  • 构建阻断补齐:当前工作区已有 AppState.editor_actor / AppConfig.enable_editor_actor 脏改动但缺少真实 editor_actor.rs 文件,导致 mnote-web 无法编译启动;本轮把 misplaced 的 EditorRuntimeActor 实现补到 rust/crates/mnote-web/src/editor_actor.rs,并补齐测试配置中的 enable_editor_actor 字段,以恢复 3000 验证入口。
  • GREEN 证据:重新启动最新 desktop:hot 后运行 MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task446-tree-rename-dual-browser-live-smoke.js 通过。证据 tmp/tree-live-cache-smoke/20260516-task446-rename/result.json,截图 tmp/tree-live-cache-smoke/20260516-task446-rename/b-document-after-rename.pngtmp/tree-live-cache-smoke/20260516-task446-rename/b-filetree-after-rename.png
  • 验证结果:B 文档页 documentTitle/titleInputValue/breadcrumbTitle/sidebarTitle 均为新裸标题;B File Tree fileTreeTitle={renamedTitle}.md;两端 liveApplied=deltaliveError=""rename 后 navigationEvents=[],确认 B 端无刷新 / 无导航。
  • 缺陷记录:bugs/05-editor-mainline/done/5-13-tree-rename-live-document-chrome-stale-v1.md

2026-05-16 双浏览器 move order live cache 修复与验证记录:

  • 新增 regression smokescripts/task447-tree-move-order-dual-browser-live-smoke.js。脚本使用 A/B 独立 browser contextA 端创建同父级 A/B/C 后执行正式 /api/tree/commands{ action: "move", documentId: C, parentId: root, sortOrder: 1 },B 端分别保持目标文档页与 File Tree 页面不刷新,记录 direct child order、tree events、导航事件与截图路径。
  • RED 证据:合法 sortOrder=1 下修复前真实 3000 smoke 失败。B 端收到 tree:delta move_documentpayload 含 sortOrder=1liveApplied=deltaliveError="",但 Page Tree / File Tree DOM 顺序仍为 A/B/C,导致 waitForExpectedOrder 超时。
  • 根因:Rust SSR 文档 shell 的 applyMoveDocumentDelta(data) 未读取 sortOrdermoveDocumentRowForMode(mode, documentId, parentId) 固定 appendChild 到目标父节点末尾;tree:local-command optimistic move 分支也未传 body.sortOrder
  • 修复点:rust/crates/mnote-web/src/ssr/pages/layout.rs 增加 sortOrderFromDeltainsertTreeNodeAtSortOrder,让 live delta 与 local command move 按目标父节点直系 sibling index 插入;rust/crates/mnote-web/src/routes/tree.rs 补充 route/artifact 单测断言 sortOrder 保留在 result 与 streamDelta
  • GREEN 证据:重启最新 desktop:hot 后运行 MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task447-tree-move-order-dual-browser-live-smoke.js 通过。证据 tmp/tree-live-cache-smoke/20260516-task447-move-order/result.json,截图 tmp/tree-live-cache-smoke/20260516-task447-move-order/b-document-after-move.pngtmp/tree-live-cache-smoke/20260516-task447-move-order/b-filetree-after-move.png
  • 验证结果:B 文档页与 B File Tree 页面中的 Page Tree / File Tree direct child order 均从 A/B/C 变为 A/C/B;两端 liveApplied=deltaliveError=""move 后 navigationEvents=[],确认无刷新 / 无导航。
  • 缺陷记录:bugs/04-tree-domain/done/4-42-tree-move-live-delta-sort-order-ignored-v1.md

2026-05-16 SSE resync / reconnect recovery 验证记录:

  • 新增 scripts/task448-tree-resync-recovery-dual-browser-smoke.js,通过 B 端 EventSource URL 注入 pollMs=5000,A 端在同一 poll 间隔内连续创建两个子页,强制 /api/tree/events 进入非单条 delta 的 event: resync 分支。
  • task448 验证结果:B 文档页与 B File Tree 页面均收到 tree:resyncliveApplied=resyncliveError=""Page Tree / File Tree direct child order 从仅有初始子页恢复为包含新增 b/c 两个子页,navigationEvents=[]。证据 tmp/tree-live-cache-smoke/20260516-task448-resync/result.json,截图 tmp/tree-live-cache-smoke/20260516-task448-resync/b-document-after-resync.pngtmp/tree-live-cache-smoke/20260516-task448-resync/b-filetree-after-resync.png
  • 新增 scripts/task449-tree-sse-reconnect-snapshot-recovery-smoke.js,通过 Playwright context.setOffline(true) 模拟 B 端 SSE 断线,A 端离线期间连续创建两个子页,B 端恢复在线后等待 EventSource 恢复事件把 UI 拉回最新。
  • task449 验证结果:B 文档页与 B File Tree 页面恢复后 liveStatus=connectedliveApplied=resyncliveError="",新增 b/c 子页出现在 Page Tree 与 File TreenavigationEvents=[]。证据 tmp/tree-live-cache-smoke/20260516-task449-reconnect/result.json,截图 tmp/tree-live-cache-smoke/20260516-task449-reconnect/b-document-after-reconnect.pngtmp/tree-live-cache-smoke/20260516-task449-reconnect/b-filetree-after-reconnect.png
  • 说明:当前 Rust SSR controller 的真实恢复合同是“断线期间错过多条变化后,恢复时通过 snapshot/resync 类完整投影拉回 UI”;本轮实测恢复事件为 tree:resync,不是浏览器刷新或导航。

验证命令建议:

cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_events
node --check scripts/task447-tree-move-order-dual-browser-live-smoke.js
node --check scripts/task448-tree-resync-recovery-dual-browser-smoke.js
node --check scripts/task449-tree-sse-reconnect-snapshot-recovery-smoke.js
node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js
node scripts/task432-filetree-trash-page-dual-browser-no-refresh-smoke.js
node scripts/task446-tree-rename-dual-browser-live-smoke.js
node scripts/task447-tree-move-order-dual-browser-live-smoke.js
node scripts/task448-tree-resync-recovery-dual-browser-smoke.js
node scripts/task449-tree-sse-reconnect-snapshot-recovery-smoke.js

3.5 定向 Bug Hunt

  • 建立 bugs 分类:Page Aggregate 问题归 bugs/05-editor-mainline/process/
  • Tree command / realtime / File Tree 问题归 bugs/04-tree-domain/process/
  • AI tools 问题归 bugs/07-ai/process/
  • 每个 bug 必须包含复现步骤、期望、实际、证据截图或 JSON、owner 判断。
  • 先补最小 failing smoke 或定向单测,再修实现。
  • 修复后移动到对应 done/,并记录验证命令。

重点 bug 方向:

  • Page Aggregate 与页头标题不一致。
  • Page Aggregate 与 File Tree {title}.md 不一致。
  • AI 写入成功但 Page Aggregate 回读旧内容。
  • stale revision 未阻断写入。
  • tree stream 断线恢复后 UI 停在旧快照。
  • 旧 compat / debug route 在 3000 首屏被误用。

2026-05-18 定向 bug hunt 收口:

  • find bugs -path '*/process/*' -type f | wc -l 结果为 0
  • 本轮 P0 / 内核优先缺陷已迁入 bugs/*/done/,并在 CURRENT_ARCHITECTURE.mddesign/10-review/done/10-current-mnote-ai-runtime-review-v1.mddesign/10-review/done/11-current-full-architecture-review-v1.md 中同步验证证据。

3.6 2026-05-16 暂停交接进展摘要

本轮按用户要求暂停继续实现,只记录当前进展与恢复点;未继续推进 3.2 Page Block AI Tooling 的实现或 smoke。

已完成到可继续接力的阶段:

  • 3.1 Page Aggregate 单一真源 已完成本 checklist 中的当前验证项,并补齐真实 3000 smoke、Rust route 测试、前端单测和失败降级证据。关键证据包括 tmp/page-aggregate-single-truth-smoke/20260516-182244/tmp/page-aggregate-body-sync-smoke/mp87mgz7.jsontmp/page-aggregate-options-sync-smoke/mp87y6j3.jsontmp/page-aggregate-refresh-persistence-smoke/mp88fr6k.json
  • 3.3 Tree Command Cutover 已完成当前收口:3000 主链使用 tree.* preferred commanddocuments.* 保留为 compat alias,并在 Rust execution plan / artifact 中标记 owner、preferredCommandName、compatCommandName、deprecatedAlias。
  • 3.4 Tree Realtime Live Cache 已完成本轮重点验证与修复:snapshot/delta/resync payload 覆盖、双浏览器新建 / 归档 / 恢复 / purge、rename 当前文档 chrome 同步、move sortOrder live 排序、SSE resync 与 reconnect recovery。
  • 本轮新增或更新的 Tree Realtime 关键证据:
    • tmp/tree-live-cache-smoke/20260516-task432/result.json
    • tmp/tree-live-cache-smoke/20260516-task446-rename/result.json
    • tmp/tree-live-cache-smoke/20260516-task447-move-order/result.json
    • tmp/tree-live-cache-smoke/20260516-task448-resync/result.json
    • tmp/tree-live-cache-smoke/20260516-task449-reconnect/result.json
  • 本轮已归档的缺陷:
    • bugs/04-tree-domain/done/4-41-tree-node-purge-command-protocol-leaks-to-convex-v1.md
    • bugs/04-tree-domain/done/4-42-tree-move-live-delta-sort-order-ignored-v1.md
    • bugs/05-editor-mainline/done/5-12-page-options-refresh-runtime-attrs-v1.md
    • bugs/05-editor-mainline/done/5-13-tree-rename-live-document-chrome-stale-v1.md

当前暂停点:

  • 已进入 3.2 Page Block AI Tooling 的只读审计阶段,但尚未勾选 3.2 的任何新 checkbox。
  • 已确认现有代码中 mnote.doc.fetch 已支持 scope=selectionformat=page_xml/text/markdown/jsonschema=mnote.page_ai_context.v1allowedTargetBlockIds、truncation/warnings/continuation 等基础字段;mnote.block.fetch 已支持 format=page_xml/textmanifest 已包含 readonly/destructive/idempotent/requiresApproval/approvalMode/runtimeOwner/writeOwner/selectionEffect 等 annotations。
  • 已确认 scripts/task-page-block-ai-tools-smoke.js 覆盖基础块工具闭环,但还没有专门覆盖 scope=selectionpage_xml/text、manifest annotations、选区外写入阻断、review session / conflict / idempotency 的完整验收。
  • 用户目标中提到的 design/07-ai/process/7-11-blocknote-tiptap-ai-reference-and-mnote-ai-tool-runtime-v1.md 当前在 design/07-ai/process/ 下不存在;实际可读历史参考位于 design/old/07-ai/process/7-11-blocknote-tiptap-ai-reference-and-mnote-ai-tool-runtime-v1.md,当前执行口径应继续以 design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md 为准。

恢复时的下一步建议:

  • 继续从 3.2 Page Block AI Tooling 开始,不要跳到定向 bug hunt。
  • 优先新增一个聚焦 smoke,例如 scripts/task-page-block-ai-context-format-smoke.js,只验证基础底座,不扩新 AI 功能:
    • manifest annotations 中 mnote.doc.fetch / mnote.block.fetch / mnote.block.replace / mnote.page.save 的 readonly、destructive、requiresApproval、selectionEffect、owner 字段。
    • mnote.doc.fetch scope=selection selectedBlockIds=[...] format=page_xml 只返回选区块,返回 schema=mnote.page_ai_context.v1allowedTargetBlockIdsrevisionRef
    • mnote.doc.fetch scope=selection format=text 不包含未选中块。
    • mnote.block.fetch format=page_xml/text 返回稳定块内容和 revisionRef
    • 选区冻结后写工具尝试修改 allowedTargetBlockIds 外块时返回 mnote_block_target_out_of_scope
  • 配套验证建议从这些命令开始:
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools -- --nocapture
node --check scripts/task-page-block-ai-context-format-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-context-format-smoke.js

交接注意事项:

  • 当前工作区有大量既有未提交改动和文件迁移,继续执行时必须只碰当前小项相关文件,不要回滚、删除或清理无关脏文件。
  • git diff --check 全仓可能仍会被既有删除文件阻断;验证本轮改动时可先用限定路径或 git diff --no-index --check /dev/null <new-file>
  • rust/crates/mnote-web/src/ssr/pages/layout.rs 中已有 Tree Realtime rename / move order 相关改动,同时可能混有先前 editor actor 相关改动;继续改动前必须重新读 diff,避免覆盖用户或前序 agent 的更改。
  • 3000 相关 smoke 必须继续保留 JSON / 截图证据路径,并在本 checklist 与对应 design/07-aibugs/* 文档同步记录。

4. 当前不优先做

  • 不优先增加新的编辑器 UI 大功能。
  • 不优先新增 AI Agent 工作流功能。
  • 不优先扩展 AI 功能面;AI 只做基础上下文、工具合同、审阅会话、冲突与回滚。
  • 不优先大规模替换 Convex。
  • 不优先重写 leptos-tiptap 输入层。
  • 不把 mnote.page.save 包装成精确块编辑长期方案。
  • 不在 compat route 继续扩写长期业务语义。
  • 不把 BlockNote / Tiptap AI runtime 作为 mnote runtime 依赖。
  • 不把 direct_block_edit_operations / local_rule planner 当作当前或长期 AI 编辑路径;简单正文编辑当前主路径是 mnote.doc.markdown_edit
  • 不新增 mnote.block.* 工具;mnote.block.* 保留为结构性辅助,不做块操作向新工具的扩张。

2026-05-18 静态边界核验证据:

  • rg -n "mnote\\.block\\.[a-zA-Z0-9_]+" rust/crates/mnote-web/src/hermes_tools rust/crates/mnote-web/src/routes/hermes_tools.rs scripts/reasonix-acp-wrapper.mjs | ... | sort -u 仅发现既有 mnote.block.fetch/delete/replace/insert_after/move_after,本轮未新增 mnote.block.* 工具。
  • page_ai_workflow.rs 注释与当前实现仍指向 mnote.doc.markdown_editdirect_block_edit_operations 只保留为历史/测试辅助,不作为当前主路径。
  • mnote.page.save 在 manifest / 7-10 / 7-12 / 本 checklist 中继续描述为页面级粗粒度兜底,不是精确块编辑主入口。
  • 未引入 @blocknote/xl-ai、BlockNote AIExtension 或新的 AI Agent workflow;本轮改动仅限 Hermes tools 合同、阻断矩阵测试和 checklist 证据。

2026-05-18 7-12 runtime 口径闭合证据:

  • design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md 已明确 7-11 旧“自有 AI runtime”口径移入 design/old/07-ai/process/,当前执行口径以 7-12 为准。
  • 7-12 已定义 PageAIContextBuilderMnoteAIToolManifestProviderPageAICommandRouterPageAIReviewSession 的边界,并明确 Phase C review / streaming apply 只做设计冻结,当前不实施。
  • 7-12 Phase B 到 Phase F 保留 manifest / router / review session / event / smoke 的后续 checklist;其中 selection 外写入 blocked 已有真实 smoke 证据,其余未实施项继续保留未勾。

2026-05-18 7-10 剩余真实页面矩阵拆分:

  • 新增 design/07-ai/process/7-16-page-block-ai-real-smoke-followup-matrix-v1.md,专门承接 7-10 中仍未完成的真实 3000 smoke 和 UI/review 边界矩阵。
  • 7-10 继续保留为页面块 AI 工具执行总 checklist7-16 只用于后续真实页面证据补齐,不扩新 AI 功能。

2026-05-18 真实页面 insert_after smoke 补充:

  • scripts/task-page-block-ai-tools-smoke.js 增加 PLAYWRIGHT_CHROME_EXECUTABLE 支持,用系统 Chromium 运行,避免当前系统无法下载 Playwright 官方 chromium 的阻断。
  • 命令:PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js
  • 证据:tmp/page-block-ai-tools-smoke/mpag4966.json,截图:tmp/page-block-ai-tools-smoke/mpag4966-page.png
  • Page Aggregatetmp/hermes-tester/page-block-ai-tools-mpag4966/page-aggregate.jsondoc/fetch/findtmp/hermes-tester/page-block-ai-tools-mpag4966/doc-fetch-find.json
  • 覆盖:mnote.block.insert_after 插入 todo 块、插入顺序、mnote.block.fetch 回读新块、重复 idempotencyKey 不二次插入、刷新后文本可见。
  • 覆盖:table_1/mindmap_1/resource_1 在 AI block projection 中返回 editable=falseunsupportedReason=复杂块暂不开放 AI 精确写入heading_parent/list_item_1/table_1/mindmap_1/resource_1plan_update block_move_after dry-run 与正式 mnote.block.move_after 均阻断,阻断后 revision / 正文不变化。

2026-05-18 真实页面 doc.fetch / doc.find / block.fetch smoke 补充:

  • 命令:PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js
  • 证据:tmp/page-block-ai-tools-smoke/mpag4966.json,截图:tmp/page-block-ai-tools-smoke/mpag4966-page.png
  • 覆盖:doc.fetch fulldoc.fetch outlinedoc.find 定位 p_2maxBlocks=2 截断、block.fetch includeChildren=true contextBefore=1 contextAfter=1 返回 revisionRef 与同父级 before/after;复杂块投影不伪装完全可编辑。

2026-05-18 真实页面 plan_update / replace / move smoke 补充:

  • 命令:PLAYWRIGHT_CHROME_EXECUTABLE=/snap/bin/chromium MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_AUTH_BASE_URL=http://127.0.0.1:3000 node scripts/task-page-block-ai-tools-smoke.js
  • 证据:tmp/page-block-ai-tools-smoke/mpag4966.json,截图:tmp/page-block-ai-tools-smoke/mpag4966-page.png
  • 覆盖:block_replace/block_insert_after/block_move_after dry-run、dry-run 不写入、blocked 场景、replace 相邻块不变与 id 保持、replace 后 Page Aggregate 回读持久化、复杂块 move 阻断、普通块 move dry-run 与正式移动、moving block id 保持、刷新后 block ids 稳定。

5. 完成定义

本 checklist 不能迁入 done/,直到:

  • Page Aggregate 的标题 / 正文 / 页面设置 / page tree / AI fetch 回读形成同一组可验证真相。
  • 7-10 的 Page Block AI Tooling 剩余矩阵完成或明确拆出后续 process 文档。
  • 7-12 的 AI 基础 runtime 口径完成:context、format、manifest annotations、review session、状态机边界都有代码或明确后续 checklist。
  • 7-14 v2 Phase A + B 当前主路径完成(mnote.doc.markdown_edit + mnote.doc.fetch 增强 + page_ai_workflow.rs 收口);Phase C 设计已冻结。设计稿修正已由 7-14 v2 与 7-187-25 bug 修复共同完成。
  • tree.* command 面对主要页面生命周期动作成为唯一 preferred runtime 主链。
  • tree realtime live cache 覆盖 Sidebar、Page Tree、File Tree、page subtree 的关键写后更新。
  • 至少一轮定向 bug hunt 完成,所有 P0/P1 blocker 已归档到 bugs/*/done/ 或明确保留为后续 process。

6. 给后续 /goal 的持续执行 Prompt

/goal objective: 持续核验 /mnt/Data1T/mnote/design/10-review/done/08-kernel-architecture-next-priority-review-and-checklist.md 的已归档结论,按 P0 -> P1 顺序推进 MNOTE 架构防回归、AI 基础底座和定向 bug hunt。每轮开始先读取 /home/lix/.codex/memories/PROFILE.md 与 ACTIVE.md,再读取 AGENTS.md、ARCHITECTURE.md、design/01-05-current-priority-overview.md、本 checklist、design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md、design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md、design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md。必须保护用户已有未提交改动,不回滚、不覆盖、不删除无关文件。优先使用多个 subagent 并行做只读审查和浏览器验证,主线程只整合证据和做小范围实现。执行顺序固定为:1) Page Aggregate 单一真源防回归;2) tree command cutover 防回归;3) tree realtime live cache 防回归;4) AI 基础工具与审阅底座,当前简单正文编辑主路径已是 `mnote.doc.markdown_edit` + `mnote.doc.fetch` + `page_ai_workflow.rs` 统一 tool executorPhase C(流式 apply + suggest/review)仅设计冻结不实施;继续补 context/selection/page_xml/tool annotations,不扩新 AI 功能;5) 定向 bug hunt。每完成一个小项都要更新对应 design/bugs 文档,补真实验证命令或证据路径。不要优先扩新功能,不要大改架构,不要把 compat/debug/fallback 当主链,不要把 BlockNote/Tiptap AI runtime 作为 mnote runtime 依赖。验证至少包含 scoped git diff --check、相关 cargo test / smoke;如涉及 3000 页面,使用 mnote-tester 或浏览器自动化并保留截图/JSON 证据。