Phase A — EditorRuntimeActor 内存缓存层 - 新增 editor_actor.rs: EditorBlockDocument 内存态 + apply_command + load_or_init - block.rs 四个写工具(replace/insert/delete/move)接入 actor 路径 - editor_actor feature flag(MNOTE_WEB_ENABLE_EDITOR_ACTOR=true 默认开启) - bridge-runtime 三个核心函数公开化 - rust-toolchain: 1.89 → stable(修复 spike WASM 编译阻塞) Phase B — 编辑器增量 delta channel - BlockDelta/DeltaOperation 类型 + actor.build_block_delta() - leptos-tiptap spike: mnote:editor:block-delta CustomEvent 监听 + JSON patch - DocumentAiAgentPanel: 拦截 blockDelta → window dispatchEvent - 工具响应含 blockDelta 字段供前端消费 Phase C — 事件 stream delta - broadcast channel 在 AppState/actor/SSE 三层贯通 - tree_events SSE 端点发 block.delta 事件 - 旧客户端降级兼容 环境修复 - rustc recursion_limit = 1024(修复 Leptos SSR 类型深度溢出) - run-convex-deploy.js(封装 Convex function 部署到本地后端 3210) ref: design/07-ai/process/7-13-page-block-editor-runtime-actor-v1.md
447 lines
41 KiB
Markdown
447 lines
41 KiB
Markdown
# 10-review 顺序执行清单与验收标准
|
||
|
||
> 执行状态:已完成并归档到 `design/10-review/done/`。本文是本轮 10-review 的最终验收依据与防回归口径,根目录 `design/10-review/README.md` 仅保留索引。
|
||
|
||
> 更新时间:2026-05-14
|
||
>
|
||
> 上游依据:
|
||
> - `/mnt/Data1T/mnote/design/10-review/README.md`
|
||
> - `/mnt/Data1T/mnote/design/10-review/done/01-rust-kernel-web-review.md`
|
||
> - `/mnt/Data1T/mnote/design/10-review/done/02-frontend-editor-tree-review.md`
|
||
> - `/mnt/Data1T/mnote/design/10-review/done/03-convex-realtime-storage-review.md`
|
||
> - `/mnt/Data1T/mnote/design/10-review/done/04-secondary-domains-and-design-governance-review.md`
|
||
> - `/mnt/Data1T/mnote/design/10-review/done/05-tree.md`
|
||
> - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md`
|
||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-12-main-editor-object-tab-resource-alignment-checklist-v1.md`
|
||
|
||
## 0. 执行前提
|
||
|
||
`05-tree.md` 中关于 Resource Tree / File Tree / Page Tree、ObjectIdentity、mindmap 与 `index.md` 隔离的核心事项已经由 `4-24` 与 `5-12` 承接到 `done/`。后续执行不要重复重做该主线,只需要保留防回归验证。
|
||
|
||
本清单按依赖顺序执行。原则是先修会影响主链一致性和数据可信度的 P0,再处理 realtime / projection / compat 收口,最后做次级域和文档治理。
|
||
|
||
## 1. P0:修正 Rust page write artifact 一致性
|
||
|
||
状态:已完成第 1 项代码侧与 Rust 3000 验证。Rust `/api/documents/title` 与 `/api/documents/options` 已切到 artifact 记录路径;`page.layout.updateOptions` 已补 tree domain event / conservative resync artifact;Rust 3000 下已直接验证标题更新后 `bridge.workspace.overview` 可读到 `page.head.updateTitle` command log 与 `tree.node.renamed` domain event,`/api/tree/events` 也能输出包含新标题的 stream 事件。完整 File Tree 标题同步仍归入第 6 项继续处理。
|
||
|
||
目标:让 3000 主入口下的页面标题、页面设置、正文保存拥有一致 side effect,确保 tree stream 能看到相关变更。
|
||
|
||
建议修改范围:
|
||
|
||
- `rust/crates/mnote-web/src/routes/documents.rs`
|
||
- `rust/crates/mnote-web/src/routes/command_support.rs`
|
||
- `rust/crates/mnote-web/src/transport/convex.rs`
|
||
- 必要时补充 `wolai-frontend/convex/bridgeLogs.ts` 查询侧验证
|
||
|
||
执行项:
|
||
|
||
- [x] 将 Rust `/api/documents/title` 的命令执行切到 artifact 记录路径,或统一复用正式 page/tree command route。
|
||
- [x] 将 Rust `/api/documents/options` 的命令执行切到 artifact 记录路径,或统一复用正式 page/tree command route。
|
||
- [x] 明确 artifact 写失败策略:主 mutation 成功但 artifact 失败时至少要有可观测错误,并触发保守 resync 或明确降级。
|
||
- [x] 补回归测试:标题更新后,`bridgeLogs:listWorkspaceOverview` 能看到对应 command/domain event。
|
||
|
||
验收标准:
|
||
|
||
- [x] `cargo test -p mnote-web documents_title -- --nocapture` 或等价标题 route 测试通过。
|
||
- [x] `cargo test -p mnote-web documents_options -- --nocapture` 或等价页面设置 route 测试通过。
|
||
- [x] 手动或脚本验证:更新标题后 `/api/tree/events` 输出 delta 或 resync,不需要刷新整页才能看到 sidebar/breadcrumb 变化。
|
||
- [x] Rust route 与 Next legacy adapter 对同一 page write 的 canonical command / artifacts 语义一致。
|
||
|
||
证据:
|
||
|
||
- `rust/crates/mnote-web/src/routes/documents.rs`:`title` / `options` 使用 `execute_runtime_command_via_convex_with_artifacts`,响应 `meta.artifacts` / `meta.artifactError`。
|
||
- `rust/crates/bridge-runtime/src/lib.rs`:`page.layout.updateOptions` 产生 `page.layout.options_updated` domain event 与 `resync_required` stream delta。
|
||
- `rust/crates/mnote-web/src/transport/convex.rs`:发送给 legacy `documents:updateOptions` 时剥离 artifact-only 字段。
|
||
- 已通过:Rust 3000 目标脚本创建临时页面后调用 `/api/documents/title`,再查 `/api/bridge/workspace?targetPageId=<documentId>&aggregateType=page&aggregateId=<documentId>`,确认返回 `command_name=page.head.updateTitle` 与 `event_type=tree.node.renamed`。
|
||
- 已通过:Rust 3000 目标脚本创建临时页面后调用 `/api/documents/title`,再查 `/api/tree/events?workspaceId=<workspaceId>&maxPolls=1&pollMs=250`,确认 stream 文本包含新标题且包含 `snapshot` / `delta` / `resync` 事件。
|
||
- 已通过:`node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js`。
|
||
- 部分通过:`node scripts/task110-page-title-single-truth-smoke.js` 在 Rust 3000 下已通过页头、breadcrumb、sidebar、page tree 标题一致性检查;当前失败点为 File Tree 标题行,继续归入第 6 项处理。
|
||
- 已通过:`pnpm test -- src/app/api/documents/route-adapters.test.ts src/lib/documents/page-write-command-adapter.test.ts`(Vitest 实际执行 112 个测试文件、457 个测试),Next `documents/title` route 与 page write adapter 继续生成 `page.head.updateTitle` canonical command 并进入 Rust artifact writer。
|
||
- 已通过:`cargo test -p mnote-web documents_ -- --nocapture`。
|
||
- 已通过:`cargo test -p bridge-runtime page_head_update_title_command_plan_uses_canonical_page_command -- --nocapture`。
|
||
- 已通过:`cargo test -p bridge-runtime page_layout_update_options_command_plan_uses_canonical_page_command -- --nocapture`。
|
||
- 已通过:`cargo test -p bridge-runtime document_options_command_plan_maps_to_documents_update_options -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web convex_command_args_strips_page_options_artifacts_for_legacy_mutation -- --nocapture`。
|
||
|
||
## 2. P0:移除或显式隔离假 fallback 数据
|
||
|
||
状态:已完成代码侧收口与负向单测。Search 默认不再返回内置固定业务结果;workspace shell projection 默认进入 degraded empty;Sidebar/File Tree dev fallback 仅在 `allow_dev_fixtures` 开启时可用,并带隐藏 debug/dev 标识。
|
||
|
||
目标:失败、超时、Convex 不可用时,不再返回看起来像真实业务数据的 fixture / fallback。
|
||
|
||
建议修改范围:
|
||
|
||
- `rust/crates/mnote-web/src/routes/search.rs`
|
||
- `rust/crates/mnote-web/src/routes/web_shell.rs`
|
||
- `rust/crates/mnote-web/src/routes/snapshot_support.rs`
|
||
|
||
执行项:
|
||
|
||
- [x] 优先移除或强门禁 Search 的 `fallback_search_dataset`。
|
||
- [x] 对 workspace shell projection 加载失败的最小合成数据做决策:返回明确 degraded/empty/error,不能伪装成真实 workspace projection。
|
||
- [x] 对 `allow_dev_fixtures` 相关 sidebar/filetree fallback 增加明确 debug/dev 标识,并确认 3000 默认启动链不会误开。
|
||
- [x] 增加负向 smoke:Convex/query 不可用时,Search、Sidebar、File Tree 不返回固定假业务数据。
|
||
|
||
验收标准:
|
||
|
||
- [x] 关闭或破坏 Convex query 后,Search 不返回内置固定结果。
|
||
- [x] 关闭或破坏 projection 加载后,workspace/sidebar/filetree 响应带明确错误、空状态或 degraded 标记。
|
||
- [x] 3000 默认入口不会出现 fixture workspace、fixture document、fixture filetree row。
|
||
- [x] 相关负向测试或 smoke 在失败场景下能稳定断言“不返回假数据”。
|
||
|
||
证据:
|
||
|
||
- `rust/crates/mnote-web/src/routes/search.rs`:Convex/search query 失败时,默认返回空结果与 `meta.degraded=true`;仅 `allow_dev_fixtures` 开启时使用 `fallback_search_dataset`。
|
||
- `rust/crates/mnote-web/src/routes/web_shell.rs`:workspace shell projection 失败时,默认返回 degraded empty dataset;Sidebar/File Tree dev fallback HTML 增加 `data-mnote-dev-fixture` 标识。
|
||
- `rust/crates/mnote-web/src/workspace_shell.rs`:workspace shell projection/render 支持 `degraded` / `devFixture` 标识。
|
||
- 已通过:`cargo test -p mnote-web search_ -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web sidebar_and_filetree_do_not_return_dev_fixtures_by_default -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web workspace_shell_sidebar_html_marks_degraded_and_dev_fixture_states -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web document_shell_returns_page_aggregate_snapshot -- --nocapture`。
|
||
|
||
## 3. P1:补齐 OnlyOffice Rust callback / forcesave 写回链
|
||
|
||
状态:已完成代码侧与真实 Rust 3000 smoke。Rust `/api/onlyoffice/callback` 与 `/api/onlyoffice/forcesave` 已改为显式代理 legacy Next 写回链;未配置 legacy Next 时返回明确失败/unsupported,不再静默 no-op 成功;`task174` 已验证 OnlyOffice 附件打开链路与 docKey。
|
||
|
||
目标:Rust Web 主入口下 OnlyOffice 保存不能出现“返回成功但未写回”的情况。
|
||
|
||
建议修改范围:
|
||
|
||
- `rust/crates/mnote-web/src/routes/onlyoffice.rs`
|
||
- `rust/crates/adapter-onlyoffice/`
|
||
- `wolai-frontend/src/app/api/onlyoffice/callback/route.ts` 作为 legacy 写回参考
|
||
- `scripts/task174-rust-onlyoffice-attachment-open-smoke.js`
|
||
|
||
执行项:
|
||
|
||
- [x] 决定 Rust route 直接写回,还是显式代理到 legacy Next 写回链。
|
||
- [x] 如果直接写回,接入 media asset / storage 写回与 callback 状态处理。(本轮选择显式代理 legacy Next 写回链,直接写回不适用。)
|
||
- [x] forcesave 不再返回纯 `mnote-web-rust-noop` 成功语义;若仍未支持,必须返回明确 unsupported/degraded。
|
||
- [x] 补真实浏览器 smoke:打开 OnlyOffice 附件、触发保存、重新打开后内容或版本可验证。
|
||
|
||
验收标准:
|
||
|
||
- [x] `/api/onlyoffice/callback` 在需要写回的 status 下会产生真实持久化写入或明确失败。
|
||
- [x] `/api/onlyoffice/forcesave` 不再静默 no-op 成功。
|
||
- [x] `node scripts/task174-rust-onlyoffice-attachment-open-smoke.js` 或等价 smoke 通过。
|
||
- [x] 3000 主链不会 shadow 掉 legacy Next 的真实写回能力。
|
||
|
||
证据:
|
||
|
||
- `rust/crates/mnote-web/src/routes/onlyoffice.rs`:callback / forcesave 代理到 `legacy_next_base_url` 的 Next `/api/onlyoffice/*` 写回链;缺少 legacy 写回链时返回明确失败。
|
||
- 已通过:`cargo test -p mnote-web onlyoffice_ -- --nocapture`。
|
||
- 已通过:`node scripts/task174-rust-onlyoffice-attachment-open-smoke.js`,输出 `ok=true`,创建临时 docx attachment,打开 `/onlyoffice` 编辑 URL,并返回稳定 `docKey`。
|
||
|
||
## 4. P1:收口 Page Aggregate provenance
|
||
|
||
状态:已完成代码侧与文档侧收口。`/api/page-aggregate/:id` 继续保持 Rust `mnote.page_aggregate.v1` 主读链,但当底层由 `documents:getMeta + documents:getContent` substrate 构建时,response `source` 与 owner header 已明确标为 `CompatMetaContentJoin` / `compat-join`,不再误写成完整 `KernelProjection`。
|
||
|
||
目标:Page Aggregate 读链保持 Rust-first,但来源标识必须反映真实构建路径,避免把 `meta/content join` 写成完整 kernel-native projection。
|
||
|
||
建议修改范围:
|
||
|
||
- `rust/crates/core-protocol/src/page_aggregate.rs`
|
||
- `rust/crates/bridge-runtime/src/lib.rs`
|
||
- `rust/crates/mnote-web/src/routes/web_shell.rs`
|
||
- `wolai-frontend/src/lib/documents/page-aggregate-loader.ts`
|
||
- `design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
|
||
- `design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
|
||
|
||
执行项:
|
||
|
||
- [x] 明确 `PageAggregateSource::KernelProjection` 与 `CompatMetaContentJoin` 的边界。
|
||
- [x] 如果 route 仍由 `getMeta + getContent` 构建,返回 source 或 response header 应反映真实来源。
|
||
- [x] 文档更新为“Rust route 主读链已成立,底层仍是 Rust runtime adapter 消费 meta/content substrate”。
|
||
- [x] 保留或删除 `PageAggregateSource::Fixture` 前,先确认测试和本地 fixture 依赖。(本轮保留,仅用于测试或显式 dev fixture 语义。)
|
||
|
||
验收标准:
|
||
|
||
- [x] `/api/page-aggregate/:id` 返回的 source/provenance 与实际构建路径一致。
|
||
- [x] 文档中不再出现“Page Aggregate 已完全 kernel-native projection 闭环”的过满表述。
|
||
- [x] 前端 loader 仍只消费 `mnote.page_aggregate.v1`,不恢复 TS runtime builder 主链。
|
||
- [x] Page Aggregate provenance 变更有 Rust 单测或 loader 单测覆盖。
|
||
|
||
证据:
|
||
|
||
- `rust/crates/bridge-runtime/src/lib.rs`:`page.aggregate.get` 根据 query data 是否包含 `meta + content` 选择 `CompatMetaContentJoin`,否则保留 `KernelProjection`。
|
||
- `rust/crates/mnote-web/src/routes/web_shell.rs`:`/api/page-aggregate/:id` 测试断言 `x-mnote-page-aggregate-owner=compat-join` 且 `result.source=CompatMetaContentJoin`。
|
||
- `design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`:补充 Rust route 主读链与完整 kernel-native projection 的边界。
|
||
- `design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`:补充 `CompatMetaContentJoin` / `KernelProjection` 验收口径。
|
||
- `design/05-editor-mainline/done/5-5-1-page-aggregate-contract-v1.md`:新增 `source` / provenance 契约说明。
|
||
- 已通过:`cargo test -p bridge-runtime page_aggregate_get_query_executes_into_core_projection -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web page_aggregate_endpoint_returns_snapshot_contract -- --nocapture`。
|
||
|
||
## 5. P1:优化 tree stream 的 Convex 查询模型
|
||
|
||
状态:已完成代码侧与基础 Rust 3000 smoke。`bridgeLogs:listWorkspaceOverview` 已从全量 workspace collect 后内存分页,改为基于 `workspace_id + created_at + id` 及常用过滤组合索引的有界窗口查询;Rust `/api/tree/events` 的 snapshot/delta/resync 协议未改,polling-backed SSE 仍按“最新窗口 + Rust cursor 比较”工作,当前定位为过渡实现。`task123` 和标题更新目标脚本已证明 Rust 3000 stream 可输出 snapshot / title event;完整浏览器 tree integration smoke 仍因 sidebar row 可见性失败,归入第 6 项继续处理。
|
||
|
||
目标:让 `/api/tree/events` 可以长期承载主链,避免 SSE 轮询叠加全量日志扫描。
|
||
|
||
建议修改范围:
|
||
|
||
- `wolai-frontend/convex/bridgeLogs.ts`
|
||
- `wolai-frontend/convex/schema.ts`
|
||
- `rust/crates/mnote-web/src/routes/sse.rs`
|
||
- `rust/crates/mnote-web/src/routes/stream_support.rs`
|
||
- `wolai-frontend/src/lib/tree-stream/`
|
||
|
||
执行项:
|
||
|
||
- [x] 为 `command_logs` 增加按 `workspace_id + created_at/id` 的查询路径。
|
||
- [x] 为 `domain_events` 增加按 `workspace_id + created_at/id` 或 command cursor 的查询路径。
|
||
- [x] `listWorkspaceOverview` 不再每轮 collect 全量 workspace 日志后内存分页。
|
||
- [x] 明确 polling-backed SSE 是过渡实现还是长期实现;若长期使用,补连接数、日志量、延迟边界测试。(本轮明确为过渡实现,live 轮询仍查最新窗口并由 Rust 做 cursor 比较。)
|
||
|
||
验收标准:
|
||
|
||
- [x] 大量历史日志存在时,overview 查询仍按 cursor / limit 返回,不全量 collect。
|
||
- [x] `/api/tree/events` 的 snapshot/delta/resync 协议不破坏现有前端消费。
|
||
- [x] `pnpm --dir wolai-frontend test -- tree-stream` 或等价 tree-stream 测试通过。
|
||
- [x] 至少一条 smoke 覆盖标题/树变更后 SSE 能正常输出增量或保守 resync。
|
||
|
||
证据:
|
||
|
||
- `wolai-frontend/convex/schema.ts`:`command_logs` 增加 `by_workspace_created_at`、`by_workspace_status_created_at`、`by_workspace_target_page_created_at`、`by_workspace_target_block_created_at`;`domain_events` 增加 `by_workspace_created_at`、`by_workspace_status_created_at`、`by_workspace_aggregate_created_at`。
|
||
- `wolai-frontend/convex/bridgeLogs.ts`:`listWorkspaceOverview` 改为 `fetchCommandLogWindow` / `fetchDomainEventWindow`,通过索引 `order("desc").take(scanLimit)` 和 cursor 上界查询,移除对 workspace 全量日志的 `.collect()`。
|
||
- `rust/crates/mnote-web/src/routes/sse.rs`:live poll 语义保持不变,仍清空 bridge pagination cursor 后查最新窗口,再由 Rust 比较当前 stream cursor。
|
||
- 已通过:`pnpm test -- src/lib/tree-stream`(Vitest 实际执行 111 个测试文件、452 个测试)。
|
||
- 已通过:`cargo test -p mnote-web stream_ -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web tree_realtime_route_returns_rust_web_owned_snapshot_event -- --nocapture`。
|
||
- 已通过:`pnpm exec eslint convex/bridgeLogs.ts convex/schema.ts` 无错误;保留既有 `any` 风格警告。
|
||
- 已通过:`node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js`。
|
||
- 已通过:Rust 3000 目标脚本验证 `/api/documents/title` 后 `/api/tree/events?maxPolls=1&pollMs=250` 输出包含新标题的 stream 事件。
|
||
- 未通过:`node scripts/task120-rust-web-tree-integration-smoke.js` 在等待 child sidebar row 可见时超时,完整浏览器 tree integration 继续归入第 6 项处理。
|
||
- 受既有问题阻塞:`pnpm exec tsc --noEmit --pretty false` 仍被 `.next` 旧生成文件、Convex documents 类型和 mindmap/OnlyOffice 等无关类型错误阻塞;本轮新增 `bridgeLogs.ts` / `schema.ts` 未出现在错误列表中。
|
||
|
||
## 6. P1:统一 Sidebar / File Tree live cache 与主文档壳 no-refresh 验收
|
||
|
||
状态:代码侧完成,真实浏览器 create / rename / move / archive / purge 主链已通过。`usePreferredSidebarSnapshot` 已从“sync key 与 initial 对比”的特殊规则,改为基于 `getSidebarDataFreshness()` 的 version 仲裁,并保留 tree stream cursor 作为 live 元信息;`AppLayoutShell`、Sidebar、Breadcrumb、SearchPalette 继续消费同一份 preferred snapshot。Rust 3000 下已修复 `tree:delta` 的 title-only patch 被误当成空 projection 渲染的问题,`task110` 已通过页头、breadcrumb、sidebar、page tree、File Tree 标题一致性检查;`task120` 已通过 child sidebar row 可见性、rename live delta、reload 与 purge 后消失检查;`task177` 已覆盖 move / archive live DOM reducer,确认页面树与 File Tree 行局部更新后文档页头仍稳定。2026-05-14 追加验收口径:File Tree / Page Tree 的“无刷新可见”必须在 `http://127.0.0.1:3000/documents/<id>` 主文档壳验证,覆盖页面 `tree.node.create`、页面 delete/purge、页面内 mindmap create 三条链路;`/tree` debug route 与 3001/Next 路径只能作为补充排查,不能替代 3000 主入口验收。
|
||
|
||
目标:减少 `initial / query / tree_stream` 三源 freshness 选择,把 Sidebar、Breadcrumb、文档页头收口到统一 live cache / projection version 仲裁。
|
||
|
||
建议修改范围:
|
||
|
||
- `wolai-frontend/src/components/app-layout-shell.tsx`
|
||
- `wolai-frontend/src/components/sidebar/use-preferred-sidebar-snapshot.ts`
|
||
- `wolai-frontend/src/components/sidebar/sidebar.tsx`
|
||
- `wolai-frontend/src/lib/tree-stream/`
|
||
|
||
执行项:
|
||
|
||
- [x] 定义 live snapshot 的 version/cursor 仲裁字段。
|
||
- [x] `usePreferredSidebarSnapshot` 从 sync key 比较推进到 cursor/version 比较。
|
||
- [x] Sidebar、Breadcrumb、文档页头统一消费同一 preferred/live snapshot。
|
||
- [x] 保留 initial snapshot 只作为首屏启动输入,不能长期压过更新后的 stream/query。
|
||
- [x] Rust 3000 主文档壳监听 `tree:local-command`,在 `tree.node.create` / delete 成功后即时更新 Page Tree 与 File Tree DOM。
|
||
- [x] Rust 3000 主文档壳监听同页 mindmap 资产写入:slash 插入触发 `/api/mindmap/<doc>/<mindmap>` POST 成功后,File Tree 即时出现 `mindmap-<id>.json` asset row。
|
||
|
||
验收标准:
|
||
|
||
- [x] 新建、重命名、移动、归档页面后,Sidebar、Breadcrumb、文档页头无互相打架或回退闪烁。
|
||
- [x] `usePreferredSidebarSnapshot` 有单测覆盖 query、initial、tree_stream 三者的新旧仲裁。
|
||
- [x] 真实浏览器 smoke 覆盖至少一个 tree command 后 Sidebar 与文档页头一致。
|
||
- [x] 真实浏览器 smoke 必须覆盖 `3000 /documents/<id>` 主文档壳中页面新建后 Page Tree / File Tree 立即出现,且 `navigationEvents.length=0`。
|
||
- [x] 真实浏览器 smoke 必须覆盖同一主文档壳中页面删除或 purge 后 Page Tree / File Tree 立即移除,且不依赖浏览器刷新。
|
||
- [x] 真实浏览器 smoke 必须覆盖同一主文档壳中页面内新建 mindmap 后 File Tree 立即出现对应 asset row;该链路是 `/api/mindmap/<doc>/<mindmap>` 资产写入,不等同于页面 `tree.node.create`。
|
||
|
||
证据:
|
||
|
||
- `wolai-frontend/src/components/sidebar/use-preferred-sidebar-snapshot.ts`:输出 `version` 与 `cursor`,以 `getSidebarDataFreshness()` 比较 initial/query/tree_stream;stream fallback 时不参与仲裁,同版本时优先 live stream。
|
||
- `wolai-frontend/src/components/app-layout-shell.tsx`:向 preferred snapshot 仲裁传入 `treeStream.cursor`,Sidebar、Breadcrumb、SearchPalette 仍消费同一 preferred data。
|
||
- `wolai-frontend/src/components/sidebar/sidebar.tsx`:Sidebar 内部 fallback 路径也传入 `treeStream.cursor`。
|
||
- `wolai-frontend/src/components/sidebar/use-preferred-sidebar-snapshot.test.tsx`:新增 query 比旧 stream 更新时优先 query、stream 与 query 同版本时优先 stream 并暴露 cursor 的回归用例。
|
||
- 已通过:`pnpm test -- src/components/sidebar/use-preferred-sidebar-snapshot.test.tsx src/components/app-layout-shell.test.tsx src/components/sidebar/sidebar-sync.test.tsx`(Vitest 实际执行 111 个测试文件、454 个测试)。
|
||
- 已通过:`pnpm exec eslint src/components/sidebar/use-preferred-sidebar-snapshot.ts src/components/sidebar/use-preferred-sidebar-snapshot.test.tsx src/components/app-layout-shell.tsx src/components/sidebar/sidebar.tsx` 无错误;`sidebar.tsx` 保留既有 warning。
|
||
- 已通过:`cargo test -p mnote-web tree_realtime_route_returns_rust_web_owned_snapshot_event -- --nocapture`。
|
||
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`:`renderSidebarSnapshot` 只在 payload 明确带 projection items 时重渲染 Sidebar;单文档 `upsert_document` title patch 改为只调用 `updateTitleEverywhere()`,避免 rename delta 把 Sidebar 渲染成空树。
|
||
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`:新增 `move_document` / `remove_document` 的小型 DOM reducer,移动时更新页面树与 File Tree 行的父节点,归档时局部移除对应行。
|
||
- `rust/crates/mnote-web/src/transport/convex.rs`:tree create / rename / archive / restore / move 及 compat documents mutation 发送给 legacy Convex mutation 前剥离 artifact-only 字段,避免 validator 因 `streamDeltaHint` / `domainEventPlan` 返回 502。
|
||
- 已通过:`cargo test -p mnote-web sidebar_tree_runtime -- --nocapture`。
|
||
- 已通过:`cargo test -p mnote-web convex_command_args_strips -- --nocapture`。
|
||
- 已通过:`node scripts/task110-page-title-single-truth-smoke.js` 在 Rust 3000 下通过页头、breadcrumb、sidebar、page tree、File Tree 标题一致性检查。
|
||
- 已通过:`node scripts/task120-rust-web-tree-integration-smoke.js` 在 Rust 3000 下通过 root/child row、active 切换、rename live delta、reload 与 purge 检查。
|
||
- 已通过:`node scripts/task112-tree-rust-family-regression-smoke.js`,但当前页面选项壳缺少 move/embed 入口导致 picker 部分 skipped:`move_embed_entry_missing_in_current_page_options_shell`。
|
||
- 已通过:`node scripts/task177-tree-move-archive-live-smoke.js`,覆盖 `move_document` live event 后页面树 / File Tree 行 `data-parent-id` 更新,以及 `remove_document` live event 后两棵树局部移除归档行;文档页头和标题输入保持根页面标题稳定。
|
||
- 已通过:`node scripts/task179-tree-create-delete-no-reload-smoke.js`,覆盖 Rust `/tree` `convex_workspace` 下 File Tree create/delete 与 Page Tree create;该脚本只作为 debug route 补充证据,不再代表最终主链验收。
|
||
- 已通过:`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task426-mnote-web-main-no-reload-smoke.js`,覆盖 `3000 /documents/<id>` 主文档壳:页面 create/delete 无刷新即时更新 Page Tree / File Tree,页面内 mindmap create 经 `/api/mindmap/<doc>/<mindmap>` POST 后即时插入 `asset:<mindmapId>` File Tree row,`afterMindmapCreate.localApplied=true`。
|
||
|
||
## 7. P1:明确 `pageSubtree` 与本地正文编辑关系
|
||
|
||
状态:已完成。策略已固定为:server `pageSubtree` 仍是正式 projection 来源;当本地标题草稿或正文快照与 server snapshot 不一致时,前端允许用当前本地 content 生成临时 `pageSubtree`,并通过 `pageSubtreeSource=local` 暴露给 AI context,避免继续复用旧 server subtree 或让 AI 长期失去结构上下文。React `DocumentAiAgentPanel` 侧已有 client state / runtime 单测覆盖;Rust 3000 当前文档页使用全局浮动页面 AI,本轮已补同等 local `pageSubtree` context 构造与真实浏览器 smoke。
|
||
|
||
目标:用户正常编辑正文后,AI 面板、阅读视图、结构视图不能因为本地 content 与 server snapshot 不同而长期失去结构上下文。
|
||
|
||
建议修改范围:
|
||
|
||
- `wolai-frontend/src/components/editor/page-aggregate-client-state.ts`
|
||
- `wolai-frontend/src/components/editor/document-content.tsx`
|
||
- `wolai-frontend/src/lib/documents/page-subtree.ts`
|
||
- `rust/crates/core-protocol/src/page_aggregate.rs`
|
||
|
||
执行项:
|
||
|
||
- [x] 决定 `pageSubtree` 是 server-only projection,还是允许本地临时 projection。
|
||
- [x] 标记本地临时 projection 与 server projection 的来源差异,避免把本地临时结构误认为 kernel projection。
|
||
- [x] AI 面板读取最新 page aggregate snapshot 时,能拿到本地编辑后的结构上下文。
|
||
- [x] 真实编辑器 smoke 验证本地正文编辑后阅读态结构 / AI context 不丢失。
|
||
|
||
验收标准:
|
||
|
||
- [x] 本地正文或标题草稿变化后,不再继续复用旧 server `pageSubtree`。
|
||
- [x] 本地正文或标题草稿变化后,可生成临时 `pageSubtree` 供阅读态 / AI context 使用。
|
||
- [x] AI context 明确带 `pageSubtreeSource`,可区分 `server` / `local` / `none`。
|
||
- [x] 浏览器实测:编辑正文标题或 heading 后,结构面板 / AI context 能看到本地最新结构。
|
||
|
||
证据:
|
||
|
||
- `wolai-frontend/src/components/editor/page-aggregate-client-state.ts`:新增 `PageAggregateClientPageSubtreeSource`,server 快照未变时返回 `source=server`;本地 content/title 草稿变化时用 `buildPageSubtreeProjection` 生成 `source=local`。
|
||
- `wolai-frontend/src/components/editor/DocumentAiAgentPanel.tsx`:`PageAggregateAiSnapshot` 增加 `pageSubtreeSource`。
|
||
- `wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx`:AI request context 增加 `pageSubtreeSource`。
|
||
- `wolai-frontend/src/components/editor/page-aggregate-client-state.test.ts`:覆盖本地正文/标题变化后生成临时 `pageSubtree`,以及 server snapshot 下 `pageSubtreeSource=server`。
|
||
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`:历史 Rust 3000 全局浮动页面 AI 曾在发送旧 `/api/ai-agent/run` 前读取当前 Leptos/Tiptap 编辑器 DOM;当本地内容与 server aggregate 正文不同,生成 `source=local` 的临时 subtree / outline / evidence,并在 context 中发送 `pageSubtreeSource=local`。2026-05-14 起这只保留为历史上下文证据;当前页面 AI 主链已改为 Hermes client proxy,页面上下文进入 Hermes run/session context,最新页面事实由 Hermes 通过 mnote plugin tool 回读。
|
||
- 已通过:`pnpm test -- src/components/editor/page-aggregate-client-state.test.ts src/components/editor/DocumentAiAgentPanel.runtime.test.tsx src/components/editor/document-content.test.ts`(Vitest 实际执行 111 个测试文件、454 个测试)。
|
||
- 已通过:`node scripts/task178-page-ai-local-subtree-context-smoke.js`,Rust 3000 下打开真实文档页,把编辑器内容改成本地 heading 后打开页面 AI,并拦截旧 `/api/ai-agent/run` 请求确认 `context.pageSubtreeSource=local`、`documentBlocks` / `outline` / `subtree.stats.headingCount` 均包含本地最新 heading。该 smoke 已在 2026-05-14 默认退役为 historical smoke,脚本现本机归档于 gitignored `recycle/scripts/retired-ai-agent-run-smokes/`;当前页面 AI 长期验收以 `scripts/task-hermes-page-ai-*.js` 和 `scripts/task-page-block-ai-tools-smoke.js` 矩阵为准。
|
||
- 已通过:`pnpm exec eslint src/components/editor/page-aggregate-client-state.ts src/components/editor/page-aggregate-client-state.test.ts src/components/editor/DocumentAiAgentPanel.tsx src/components/editor/DocumentAiAgentPanel.runtime.tsx` 无错误;`DocumentAiAgentPanel.runtime.tsx` 保留既有 `any` warning。
|
||
|
||
## 8. P2:清理或标注 stale mapping / legacy compat
|
||
|
||
状态:已完成。`/api/documents/page` 与 `/api/mnote-web/stream` 已经明确退场为 410 compat 边界;`storage-convex-bridge` 不再把 `page.aggregate.get` 映射到不存在的 Convex `documents:getPageAggregate`,而是显式落到 `queries:unknown` 边界。Rust `/api/page-aggregate/:id` 当前先读取 `documents.meta.get` / `documents.content.get`,再交给 `bridge-runtime` 的 `page.aggregate.get` 组装 core projection,不走缺失 Convex function。
|
||
|
||
目标:保留的 compat 都必须是显式迁移/调试边界;不再让后续实现误把 stale mapping 当主链。
|
||
|
||
建议修改范围:
|
||
|
||
- `rust/crates/storage-convex-bridge/src/mapping.rs`
|
||
- `rust/crates/mnote-web/src/app.rs`
|
||
- `rust/crates/mnote-web/src/routes/gateway.rs`
|
||
- `rust/crates/mnote-web/src/routes/documents.rs`
|
||
- `wolai-frontend/src/lib/documents/page-aggregate-builder.ts`
|
||
- `wolai-frontend/src/app/api/documents/page/route.ts`
|
||
- `wolai-frontend/src/app/api/mnote-web/stream/route.ts`
|
||
|
||
执行项:
|
||
|
||
- [x] 处理 `page.aggregate.get -> documents:getPageAggregate`:实现、移除或标注为 future/stale。
|
||
- [x] legacy Next proxy 保留时,命名与注释统一为 explicit migration/debug boundary。
|
||
- [x] TS `page-aggregate-builder` 保留为测试/adapter/reference,不得重新接回 runtime 主链。
|
||
- [x] 410 compat route 保持退场语义,并补负向测试防止重新启用。
|
||
|
||
验收标准:
|
||
|
||
- [x] 全仓没有生产路径调用不存在的 `documents:getPageAggregate`。
|
||
- [x] 默认 3000 主链不走 legacy Next proxy。
|
||
- [x] `/api/documents/page` 与 `/api/mnote-web/stream` 继续保持明确退场响应。
|
||
- [x] 文档和代码注释不会把 compat/fallback 描述成当前主路径。
|
||
|
||
证据:
|
||
|
||
- `rust/crates/storage-convex-bridge/src/mapping.rs`:`page.aggregate.get` 显式标注为 stale/future compat placeholder。
|
||
- `wolai-frontend/src/app/api/documents/page/route.ts`:返回 410,提示直接使用 `/api/page-aggregate/:documentId`。
|
||
- `wolai-frontend/src/app/api/mnote-web/stream/route.ts`:返回 410,提示直接使用 `/api/tree/events`。
|
||
- `design/10-review/done/03-convex-realtime-storage-review.md`:已明确指出 `documents:getPageAggregate` 目前缺少 Convex 实现,属于方向滞后或 future/stale 口径。
|
||
- `rust/crates/storage-convex-bridge/src/mapping.rs`:`page.aggregate.get` 改为 `queries:unknown`,并注释说明 page aggregate 主读链由 Rust route + `bridge-runtime` 组装,避免误触发不存在的 `documents:getPageAggregate`。
|
||
- 已通过:`rg -n "documents:getPageAggregate|getPageAggregate" rust wolai-frontend src -g '!node_modules' -g '!target'`,仅剩 mapping 注释说明,无生产调用。
|
||
- 已通过:`cargo test -p storage-convex-bridge -- --nocapture`。
|
||
- 已通过:`cargo test -p bridge-runtime page_aggregate_get_query_executes_into_core_projection -- --nocapture`。
|
||
|
||
## 9. P2:处理 Mindmap 次级未闭合项
|
||
|
||
状态:已完成。Mindmap `export` 不再映射到未受控的 `EXPORT` runtime command,UI state 继续禁用该入口;旧 `/api/mindmap-ai/expand-node` Next route 已显式退役为 410,并指向 AI Agent 内置 `mindmap_expand_node` 工具;legacy MindmapSidebar 中调用旧 route 的补完入口已从渲染层关闭。mindmap 内容保存主链仍保持 `mindmap.command.apply`,没有回退到 Page Aggregate body 保存链;真实 3000 `task169` 已通过,证明 mindmap 与 `index.md` 隔离未回归。
|
||
|
||
目标:`05-tree.md` 的 mindmap 污染 `index.md` 已完成;剩余处理能力入口与实现不一致的问题。
|
||
|
||
建议修改范围:
|
||
|
||
- `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`
|
||
- `wolai-frontend/src/lib/mindmap/simple-mind-map-bridge.ts`
|
||
- `wolai-frontend/src/app/api/mindmap-ai/expand-node/route.ts`
|
||
- `rust/crates/core-protocol/src/tool.rs`
|
||
- `rust/crates/bridge-runtime/src/lib.rs`
|
||
|
||
执行项:
|
||
|
||
- [x] 处理 Mindmap `EXPORT`:加入安全命令并补 smoke,或在 UI state 中禁用并标注延期。
|
||
- [x] 处理 Mindmap AI expand route:按 Hermes plugin / Rust bridge 重接,或显式退役该 route。
|
||
- [x] 保持 mindmap 内容保存继续走 `mindmap.command.apply`,不得回退到 Page Aggregate body 保存链。
|
||
|
||
验收标准:
|
||
|
||
- [x] UI 不展示无法执行的 Mindmap export 能力,或 export 能真实执行并有测试覆盖。
|
||
- [x] `/api/mindmap-ai/expand-node` 不再表现为“产品入口存在但稳定 501”而无说明。
|
||
- [x] `node scripts/task169-mindmap-realtime-smoke.js` 继续通过,证明 mindmap 与 `index.md` 隔离未回归。
|
||
|
||
证据:
|
||
|
||
- `wolai-frontend/src/lib/mindmap/mindmap-action-map.ts`:`export` 改为 `localView`,不再下发 `runtimeCommand: "EXPORT"`。
|
||
- `wolai-frontend/src/lib/mindmap/mindmap-ui-state.ts`:`unsupportedActionIds` 继续包含 `export`,UI state 中该入口保持禁用。
|
||
- `wolai-frontend/src/app/api/mindmap-ai/expand-node/route.ts`:旧 Next route 返回 410,`x-mnote-compat-boundary=mindmap-expand-node-route-retired`。该退役说明不再指向旧 `/api/ai-agent/run` 作为长期承接面;后续若恢复 Mindmap AI,应按 Mindmap domain 另拆 Hermes plugin / Rust bridge 迁移。
|
||
- `wolai-frontend/src/components/editor/blocks/MindmapSidebar.tsx`:legacy 侧栏中调用 `/api/mindmap-ai/expand-node` 的补完入口通过 `MINDMAP_LEGACY_EXPAND_NODE_ENTRY_ENABLED=false` 从渲染层关闭。
|
||
- 已通过:`pnpm test -- src/lib/mindmap/mindmap-action-map.test.ts src/lib/mindmap/mindmap-ui-state.test.ts src/lib/mindmap/simple-mind-map-bridge.test.ts src/app/api/mindmap-ai/expand-node/route.test.ts`(Vitest 实际执行 112 个测试文件、457 个测试)。
|
||
- 已通过:`pnpm exec eslint src/lib/mindmap/mindmap-action-map.ts src/lib/mindmap/mindmap-action-map.test.ts src/lib/mindmap/mindmap-ui-state.test.ts src/app/api/mindmap-ai/expand-node/route.ts src/app/api/mindmap-ai/expand-node/route.test.ts src/components/editor/blocks/MindmapSidebar.tsx` 无错误;保留 `MindmapSidebar.tsx` 既有 `AiPanel` 未使用 warning。
|
||
- 已通过:`cargo test -p bridge-runtime mindmap_command_apply_plan_uses_kernel_command_facade -- --nocapture`,确认 mindmap 内容保存仍走 `mindmap.command.apply` / `mindmaps:applyCommand` facade。
|
||
- 已通过:`node scripts/task169-mindmap-realtime-smoke.js`(Rust 3000 已启动,脚本退出码 0)。最终结果 `ok=true`、`failures=[]`,同一页面最终 File Tree mindmap row 数量为 1,`mindmapId=mindmap_1778695090474`,object identity 仍为同一 `objectKind:"mindmap"`。
|
||
- 已通过:`cargo test -p bridge-runtime mindmap -- --nocapture`,17 个 mindmap 相关测试通过;普通 `mindmap.command.apply` 改为 `mindmap.content.updated + noop`,`mindmaps.put createOnly=false` 也不再默认 tree resync。
|
||
- 已通过:`cargo test -p mnote-web mindmap -- --nocapture`,6 个 mindmap 相关测试通过,覆盖 Rust `/api/mindmap/:docId/:mindmapId` 的 object artifact 响应。
|
||
- 已通过:`node scripts/task169-mindmap-realtime-smoke.js` 最新结果 `ok=true`、`failures=[]`;6 条可解析普通 `mindmap.command.apply` 响应均为 `eventType=mindmap.content.updated`、`streamOp=noop`,另有 1 条 Playwright response body 读取失败被记录为 `skippedReadFailures=1`;同一页面最终仍只有 1 条 mindmap asset row,`mindmapId=mindmap_1778698542703`。
|
||
|
||
## 10. P3:文档治理与回填
|
||
|
||
状态:已完成文档侧收口。`10-review/README.md` 已指向本执行清单;`05-tree.md` 已标明 Resource Tree / ObjectIdentity / mindmap 与 `index.md` 隔离主线由 `4-24` / `5-12` 承接完成;`5-5-1` 已修正 `showHeadingNumbers` / `embedDefaultBlockId` 的 runtime payload 口径;`90-reference` 的对话式尾巴已清理,`design/README.md` 已补充参考目录不能覆盖主线设计的引用边界。
|
||
|
||
目标:让设计目录继续反映真实主线,不把参考资料或过时清单误当成当前架构。
|
||
|
||
建议修改范围:
|
||
|
||
- `design/10-review/README.md`
|
||
- `design/10-review/done/05-tree.md`
|
||
- `design/05-editor-mainline/done/5-5-1-page-aggregate-contract-v1.md`
|
||
- `design/90-reference/`
|
||
|
||
执行项:
|
||
|
||
- [x] 在 `05-tree.md` 中补充最终采用的 object editor / object tab 方案摘要,并说明核心执行已由 `4-24` / `5-12` 完成。
|
||
- [x] 修正 `5-5-1` 中 `showHeadingNumbers` / `embedDefaultBlockId` 已接入 runtime payload 的滞后描述。
|
||
- [x] 清理 `design/90-reference` 问答式残留,保留为中性参考笔记。
|
||
- [x] 在引用规范中再次强调 `90-reference` 不参与 process/done 状态判断,不是上位架构来源。
|
||
|
||
验收标准:
|
||
|
||
- [x] `design/10-review/README.md` 能指向本执行清单。
|
||
- [x] `05-tree.md` 不再让后续 worker 误以为 Resource Tree / ObjectIdentity / mindmap 止血仍未执行。
|
||
- [x] `design/90-reference` 的内容不再保留“需要我给你...”这类对话尾巴。
|
||
- [x] 主线文档对 Page Aggregate、tree realtime、ObjectIdentity 的描述与当前代码事实一致。
|
||
|
||
证据:
|
||
|
||
- `design/10-review/README.md`:补充执行入口,指向 `done/06-execution-checklist-and-acceptance.md`,并说明 `done/05-tree.md` 核心主线已由 `4-24` / `5-12` 承接。
|
||
- `design/10-review/done/05-tree.md`:开头增加执行状态,明确本文不再作为待办清单直接执行。
|
||
- `design/05-editor-mainline/done/5-5-1-page-aggregate-contract-v1.md`:`showHeadingNumbers` / `embedDefaultBlockId` 改为“runtime payload 已贯通,但深语义未完成”的口径。
|
||
- `design/90-reference/90-1-filetree.md`、`design/90-reference/90-2-yemianshu.md`:删除“需要我给你...”对话尾巴。
|
||
- `design/README.md`:补充 `90-reference/` 只能作为生态资料或背景材料,不能覆盖主线设计稿。
|
||
- `design/03-rust-web/done/3-15-runtime-fallback-retirement-checklist-v1.md`:从 `process/` 迁入 `done/`,文件自身 checkbox 已全部完成,且与第 2 / 第 8 项 fallback、compat 退场证据一致。
|
||
- `design/06-mindmap/done/6-mindmap-phase6-kmind-parity-detail-checklist-v1.md`:从 `process/` 迁入 `done/`,文件自身 checkbox 已全部完成,并已有 `task167-mindmap-kmind-parity-smoke.js` 等 Phase 6 KMind parity 证据。
|
||
- 已验证:`rg -n "需要我给你|我可以|你要不要|是否需要|请告诉我|如果你愿意|要我|我来" design/90-reference` 无匹配。
|
||
- 已完成只读状态审计:`design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md`、`design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`、`design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`、`design/06-mindmap/process/6-mindmap-kernel-phase6-projection-editor-v1.md`、`design/06-mindmap/process/6-mindmap-phase6-leptos-ui-shell-reuse-checklist-v1.md` 仍有未完成项或长期主线尾项,继续保留在 `process/`;`design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`、`design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`、`design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md`、`design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md` 已迁入 `done/`,后续活跃 AI 体验面由 `design/07-ai/process/7-7-page-ai-mini-hermes-control-surface-v1.md` 承接;`design/old/**` 不纳入活跃 process/done 迁移判断。
|
||
|
||
## 11. 全局 Done Gate
|
||
|
||
全部清单完成前,不应把 10-review 状态描述为“单一真源已完全闭环”。可以描述为:
|
||
|
||
> Rust 已经持有主语义主导权,Page Aggregate、tree command、tree realtime、Resource/ObjectIdentity 主线已经切入;剩余工作集中在 artifact 一致性、fallback 退场、realtime 查询模型、provenance 口径和 compat 边界收口。
|
||
|
||
全部完成的最低验收:
|
||
|
||
- [x] P0 两项全部完成,且有自动化测试或真实 smoke 证据。
|
||
- [x] `05-tree.md` 已执行事项通过 `task169` 或等价 smoke 防回归。
|
||
- [x] `/api/page-aggregate/:id` provenance 与真实来源一致。
|
||
- [x] `/api/tree/events` 不依赖全量日志扫描作为长期查询模型。
|
||
- [x] 3000 默认主链不返回假业务数据、不走 legacy proxy、不静默 no-op 保存。
|
||
- [x] 设计文档中的 `process/`、`done/` 状态与真实代码和验收证据一致。
|
||
|
||
## 12. 关联缺陷验收状态
|
||
|
||
本执行清单本身已完成;与本轮用户反馈直接相关的两个 bug 文档状态如下:
|
||
|
||
- `bugs/04-tree-domain/done/4-25-tree-command-create-delete-reload-latency-v1.md`:Rust `/tree` debug shell 的 create / delete 强刷新子项已关闭,`task179` 已通过无 reload 与耗时验收;React Sidebar 直接 create/delete 已改为本地更新,不再同步等待 `refreshTree()`;Rust-family React shell 的 create / rename / move host mutation 回调也已改为本地 apply,不再默认整树 refetch。文档已迁入 `done/`。
|
||
- `bugs/05-editor-mainline/done/5-11-mindmap-ghost-assets-and-tree-command-latency-v1.md`:ghost mindmap asset 增长的 NodeView document id 误归属链路已止血,`task169` 已通过同一页面单 mindmap row 与 object identity 稳定验收;普通 mindmap 节点编辑 artifact 语义已收窄为 `mindmap.content.updated + noop`;已新增 `task180` 只读候选审计脚本用于清理前取证,并支持 `/api/tree/projections/file` 的只读投影输入以审计 File Tree duplicate row。真实 File Tree projection 审计已确认当前 workspace 下 `fileTreeMindmapRows=10`、`duplicateFileTreeMindmapRows=0`、`candidateCount=0`。历史清理候选为 0,因此本轮不执行数据删除;文档已迁入 `done/`。
|