# [recycle] mnote 单仓收口 Rust 内核阶段 Checklist

> 更新时间：2026-04-14
>
> 主工作路径：`/mnt/Data1T/mnote`
>
> 第二工作路径：`/mnt/Data1T/mnote-rust`（仅作为历史资产来源，不作为主执行仓）
>
> 对齐文档：`/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/process/rust-kernel-backport-plan.md`
>
> 目标：把 `mnote-rust` 的必要 Rust 内核逐步回迁到 `mnote` 主仓，并始终维持“单仓启动、单仓保存、主前端不分叉”的执行口径。

## 1. 执行口径与硬边界

- [x] 只保留 `/mnt/Data1T/mnote` 作为唯一主产品仓。
- [x] `/mnt/Data1T/mnote-rust` 只保留为历史资产来源、参考实现和待吸收规范，不再承担主线执行入口。
- [x] `wolai-frontend` 继续承担唯一主产品前端壳，不复制 `mnote-rust` 的第二套 Next 前端壳。
- [x] Rust 内核统一收口到 `/mnt/Data1T/mnote/rust/`，不再在主仓根目录散落多个 Rust 源码根。
- [x] 最终保存只认 Convex 主事实层；Rust 的事件、索引、缓存、fixtures 都属于派生层。
- [x] 不通过跨仓软链接、硬链接或路径偷接来假装完成迁移。
- [x] 第一阶段不迁入 `design/phases/**`、`design/execution/**`、`design/UI/**` 这类历史叙事文档。
- [x] 第一阶段不迁入 `mnote-cli`、`adapter-onlyoffice`、`adapter-mindmap`、`adapter-legacy-mnote`。
- [x] Mindmap 继续以 `mnote` 当前实现为主：BlockNote 自定义块为主形态，独立全屏页为辅助形态。
- [x] OnlyOffice 继续保持“正文只嵌文件入口、编辑器在独立页面运行”的产品形态，不回嵌 BlockNote。
- [x] `wolai-frontend/`、`wolai-backend/`、`infra/convex/`、`src/components/onlyoffice/` 默认保持不动，除非后续阶段明确接线需要。

## 2. 当前已确认基线（2026-04-13 已核对）

### 2.1 已完成事实

- [x] `/mnt/Data1T/mnote/rust/Cargo.toml` 与 `/mnt/Data1T/mnote/rust/Cargo.lock` 已存在。
- [x] `/mnt/Data1T/mnote/rust/crates/` 下已落位 `core-domain`、`core-protocol`、`event-log`、`storage-convex-bridge`、`index-fts`、`bridge-runtime`、`mnote-cli`。
- [x] `/mnt/Data1T/mnote/rust/design/INDEX.md` 与 `design/core/01~04` 核心设计文档已落位。
- [x] workspace members 仅指向 `/mnt/Data1T/mnote/rust/crates/*`。
- [x] 已验证 `cargo metadata --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml --format-version 1` 可通过。
- [x] 已验证 `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml` 可通过。
- [x] 已核对 `/mnt/Data1T/mnote/rust/` 下未发现直接引用 `/mnt/Data1T/mnote-rust` 的残留路径。
- [x] 已确认当前主前端链路仍在 `mnote`：文档页为 `DocumentShell -> DocumentContent -> BlockNoteEditor`，Mindmap 仍复用现有 `MindmapBlock` 体系，OnlyOffice 仍为独立页面型编辑器。

### 2.2 当前仍未开始或未初始化的事实

- [x] `/mnt/Data1T/mnote/rust/bridge/` 已初始化最小说明目录，`crates/bridge-runtime` 已提供 Phase 1 最小真实执行样板。
- [x] `/mnt/Data1T/mnote/rust/scripts/` 当前未初始化。
- [x] `/mnt/Data1T/mnote/rust/fixtures/` 当前未初始化。
- [x] `/mnt/Data1T/mnote/rust/tests/` 当前未初始化。
- [x] `mnote-cli` 已并入 `/mnt/Data1T/mnote/rust/crates/`，当前已冻结 `page/block/search/sidebar/tool` 的最小命令面与 `--json` 输出协议。
- [x] `adapter-onlyoffice`、`adapter-mindmap`、`adapter-legacy-mnote` 尚未并入主仓。
- [x] `/api/documents/content`、`/api/documents/save`、`/api/documents/title`、`/api/documents/stats`、`/api/sidebar`、`/api/blocks/patch` 已接入主仓当前 bridge 包装层并统一返回 `request_id/trace_id` 元信息；其中 `documents/title`、`documents/stats`、`documents/options`、`documents/save` 已进一步收口到统一的 bridge mutation request 运行时接缝，可先构造与 `storage-convex-bridge::build_write_request` 对齐的 `functionName/payloadJson/args` 对象再落到 Convex，但整条链仍未直接切到 `core-protocol -> storage-convex-bridge` 的真实 Rust crate 执行链。

  2026-04-15 Phase 1/2 补记：`documents.content.get`、`documents.title.update`、`documents.save` 这 1 读 2 写链现已从主仓 Next route 真实进入 `crates/bridge-runtime`，再由 TS 仅做 Convex transport；同时 `crates/mnote-cli` 已在主仓 workspace 落位，并通过 `page/block/search/sidebar/tool` 五类最小命令面的 `--json` 计划输出冻结当前 CLI 协议。

## 3. Phase A：Rust workspace 落位（主目标已完成）

完成目标：

- `/mnt/Data1T/mnote/rust/` 成为唯一 Rust workspace 根。
- P0 crate 与核心规范文档已在主仓内有真实副本。
- 新 workspace 已具备最小自检能力。

Checklist：

- [x] 固定 `/mnt/Data1T/mnote/rust/` 为唯一 Rust workspace 根，后续 Rust 命令统一从这里发起。
- [x] 固定 workspace members 只指向 `crates/core-domain`、`crates/core-protocol`、`crates/event-log`、`crates/storage-convex-bridge`、`crates/index-fts`。
- [x] 复制并落位 `core-domain`、`core-protocol`、`event-log`、`storage-convex-bridge`、`index-fts`。
- [x] 复制并落位 `rust/design/INDEX.md` 与 `rust/design/core/01-domain-model-v0.md`、`02-command-query-tool-protocol-v0.md`、`03-storage-event-indexing-v0.md`、`04-onlyoffice-integration-boundary-v0.md`。
- [x] 统一 workspace 级别的 `edition`、`license`、`version`、`authors` 约定。
- [x] 跑通 `cargo metadata --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml --format-version 1`。
- [x] 跑通 `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml`。
- [x] 已补跑 `cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-domain` 与 `cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-protocol`。
- [x] 已在本 checklist 第 1 节固定“第一阶段禁止迁入清单”，明确 `mnote-cli`、`adapter-*`、`design/phases/**`、`design/execution/**`、第二套 Next 前端壳均不属于本阶段交付。

Phase A 验收：

- [x] Cargo 可在主仓内解析 workspace。
- [x] 主仓内已有 P0 内核与长期规范副本。
- [x] 当前未出现对第二工作路径的直接 Cargo 路径依赖。
- [x] 已完成 crate 单测与文档级禁止迁入清单，Phase A 可视为关闭。

## 4. Phase B：bridge 入口与 Convex 桥接

完成目标：

- 在 `mnote` 主仓内形成唯一 Rust command/query 入口。
- 首批读写入口从“前端 API 直接调 Convex”切到“前端 API -> Rust bridge -> Convex”。

当前起点（已确认）：

- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/content/route.ts` 当前直接 `query(api.documents.getContent)`。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/save/route.ts` 当前已改为构造稳定 envelope 后交给 `save-command-adapter` 执行。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/title/route.ts` 当前已不再直接拼 `mutation(api.documents.updateTitle)` 参数，改为构造稳定 envelope 后交给页面元信息 command adapter 执行。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/documents/stats/route.ts` 当前已不再直接拼 `mutation(api.documents.updateStats)` 参数，改为构造稳定 envelope 后交给页面元信息 command adapter 执行。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/sidebar/route.ts` 当前直接聚合多个 Convex query 结果。
- [x] `/mnt/Data1T/mnote/wolai-frontend/src/app/api/blocks/patch/route.ts` 当前直接读取文档内容、替换 block 树后回写 Convex。

Checklist：

- [x] 已在 `wolai-frontend/src/lib/documents/bridge.ts` 固定当前 bridge 入口，先由主仓 API route 统一走同一层包装。
- [x] 已固定首批 bridge envelope：`request_id`、`trace_id`、`workspace_id`、`actor`、`source`、`idempotency_key`。
- [x] 约定所有新命令和查询都先进入 `core-protocol` envelope，再转给 `storage-convex-bridge`。
- [x] 已把 `documents/content` 与 `sidebar` 两条低风险读链接入当前 bridge query 包装层。
- [x] 已把 `documents/title`、`documents/stats`、`documents/save`、`blocks/patch` 接入当前 bridge command 包装层。
- [x] 已为 `documents/title`、`documents/stats` 收口稳定的页面元信息 command adapter，冻结 route 到 Convex 之间的 payload/target/meta 映射，避免 route 继续直接耦合 `updateTitle/updateStats` 的参数细节。
- [x] 已为首批 4 条写链固定当前 `bridge -> Convex` 的函数名、payload 结构和 workspace scope；其中 `documents.title`、`documents.stats`、`documents.options`、`documents.save` 已先收口到 `buildDocumentBridgeMutationRequest` 这层最小运行时接缝，统一构造与 `storage-convex-bridge::build_write_request` 对齐的 `functionName/payloadJson/args`，再由同一执行器落到 Convex；`blocks.patch` 仍未收口到该执行层，且整条链尚未直接切到 Rust crate 内统一执行。
- [x] 已在 `wolai-frontend/convex/schema.ts` 新增 `command_logs`、`domain_events` 两张表，并新增 `wolai-frontend/convex/bridgeLogs.ts` 与 `src/lib/documents/bridge-log.ts` 承接首批写链日志落账。
- [x] 首批 4 条写链（`documents/title`、`documents/stats`、`documents/save`、`blocks/patch`）当前会在成功路径同时写入 command log 与 domain event；失败态、回滚态和统一事务性仍待后续补齐。
- [x] 当前已接入的查询链（`documents/content`、`sidebar`）保持只读，不产生写副作用。
- [x] 已统一 `documents/content`、`documents/save`、`documents/title`、`documents/stats`、`sidebar` 的首批 bridge 错误返回结构。
- [x] 当前 bridge 仅负责协议校验、请求映射与响应元信息包装，尚未吞并产品 UI 逻辑。

  2026-04-14 B 阶段补记：已在 `rust/crates/core-protocol` 中补齐 `documents.meta.get`、`documents.content.get`、`sidebar.dataset.list`、`documents.save`、`blocks.patch` 的最小 query/command 协议对象，并在 `rust/crates/storage-convex-bridge` 中补齐对应的 query/command name -> Convex function 映射与单测。当前主仓新增链路已统一先构建稳定 envelope，再由后续真实 Rust bridge 执行链消费；本轮已通过 `cargo test -p core-protocol -p storage-convex-bridge` 与 `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml` 验证协议与映射闭环。
  2026-04-14 B 阶段第三刀补记：已在 `wolai-frontend/src/lib/documents/bridge.ts` 新增 `buildDocumentBridgeMutationRequest` 与统一执行器，把 `documents.title.update`、`documents.stats.update`、`documents.options.update`、`documents.save` 进一步推进到最小可运行的 Rust bridge 风格接缝。当前这些写链会先生成与 `storage-convex-bridge::build_write_request` 对齐的 `functionName/payloadJson/args` 运行时对象，再由适配层调用 Convex mutation；配套 `src/lib/documents/bridge.test.ts` 已新增 request builder 断言，确认标题更新与正文保存两条链的运行时 request 形状稳定。

Phase B 验收：

- [x] 当前至少已有 2 条查询链（`documents/content`、`sidebar`）和 4 条写链（`documents/title`、`documents/stats`、`documents/save`、`blocks/patch`）通过当前 bridge 包装层读写 Convex。
- [x] 已补 `/api/bridge/trace`、`/api/bridge/request` 回查入口，并已切到 `wolai-frontend/convex/bridgeLogs.ts` 查询主线；`convex/audit.ts` 当前保留为并行旧实现线，不作为本轮回查入口。
- [x] 当前已接入的请求错误结构已统一到 bridge 错误响应，不再直接抛出临时调试字符串。
- [x] 本批改动只改 API route 与调用 payload，未改页面结构与 UI 外观。

建议验证：

- [x] `cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml`
- [x] 已对 `/api/documents/content`、`/api/sidebar` 做最小读链 smoke：当前主仓实例固定为 `http://127.0.0.1:3001`，`/api/sidebar` 已返回 `activeWorkspaceId=ws-smoke-temp`，新建文档后 `/api/documents/content` 可正常返回内容与 `requestId/traceId`。
- [x] 已对 `/api/documents/title`、`/api/documents/stats`、`/api/documents/save`、`/api/blocks/patch` 做最小写链 smoke：真实写入成功，且随后 `/api/documents/content` 已读回 `blocks.patch` 改写后的正文。
- [x] 已完成真实 Convex 运行前置验证：`infra/convex/docker-compose.yml` 可启动本地自托管 Convex，`pnpm exec convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping` 已通过。
- [x] 已用真实 Convex CLI 对 `bridgeLogs:recordCommandLog`、`bridgeLogs:recordDomainEvent`、`bridgeLogs:listByTrace`、`bridgeLogs:listByRequest` 做最小 smoke，确认 command log、domain event、trace/request 字段能同时落账并回查。
- [x] 已完成网页/API 级 smoke：从真实 `/api/documents/title`、`/api/documents/stats`、`/api/documents/save`、`/api/blocks/patch` 返回的 `requestId/traceId`，可继续经 `/api/bridge/trace` 与 `/api/bridge/request` 回查到对应 `command_logs/domain_events`。本轮同时修复 `src/lib/documents/bridge-log.ts` 中 `getAuthedConvexClient()` 返回值解构错误（此前会导致写链落账时报 `client.mutation is not a function`）。

## 5. Phase C：页面元信息、Sidebar 与正文保存接入

完成目标：

- 在不更换主前端壳的前提下，把文档元信息、Sidebar 聚合、BlockNote 正文保存逐步切到 Rust 协议层。
- 执行顺序严格按 `C1 页面元信息 -> C2 Sidebar 聚合 -> C3 正文保存` 推进，不跳步。

### C1 页面元信息

- [x] 已盘点并锁定文档页元信息读写边界：`src/app/(app)/documents/[id]/page.tsx` 负责元信息入口，`document-content.tsx` 负责标题/页面选项/统计信息写入，`document-shell.tsx` 仅继续透传既有 UI 壳参数。
- [x] 已锁定并接入当前 C1 最小读链：`src/app/(app)/documents/[id]/page.tsx` 原先直调 `api.documents.getMeta`，现已改为经 `GET /api/documents/meta` 进入现有 bridge query 包装层；新增的服务端 helper 仅负责透传当前请求认证/追踪头并发起同源 bridge route 请求。
- [x] 已把标题更新、页面属性、页面选项、统计信息这批低风险页面元信息操作切到统一的当前协议/适配边界：标题、统计信息、页面选项 3 条写链都已接入当前 bridge command 包装层；其中 `documents.title.update`、`documents.stats.update`、`documents.options.update` 已统一收口到 `wolai-frontend/src/lib/documents/metadata-command-adapter.ts`，route 只保留 validation、`buildDocumentBridgeContext`、`buildDocumentCommandEnvelope` 与稳定错误模型。`documents.options` 本轮不再内联 `client.mutation(api.documents.updateOptions, ...)`。同时已补齐 `rust/crates/core-protocol` 的 `UpdatePageTitle`、`UpdatePageStats`、`UpdatePageOptions` 结构与 `storage-convex-bridge` 的 command name -> Convex mutation 映射测试；2026-04-14 又进一步把这 3 条写链切到 `buildDocumentBridgeMutationRequest`，先构造与 Rust `ConvexMutationRequest` 对齐的最小运行时 request，再交给统一执行器落到 Convex，为后续真实 Rust 执行链留出稳定接缝。
- [x] 当前最小替换已保持现有页面 UI、权限判断、动态导入结构不变：`DocumentShell` 入参、`readOnly/disableDownload/disableCopy` 计算、`notFound()` 分支与页面结构保持不变，仅将元信息读取入口切到 `documents.meta` bridge query。
- [x] 已统一页面元信息链当前口径：`documents.meta` 读链与 `documents.title/stats/options` 写链均复用 `buildDocumentBridgeContext` / envelope；query payload 与 command payload 已固定 `documentId/workspaceId`，target.pageId 固定文档 business id，回传元信息统一为 `requestId/traceId/queryName|commandId|commandName`，actor/source 也统一来自 bridge context。
- [x] 已为标题更新、页面属性、统计信息补齐当前最小回归验证。
  当前最小验证：已对页面选项写链补跑相关文件 eslint / vitest，并完成真实 HTTP smoke，确认在主仓 `http://127.0.0.1:3001` 实例下以 `ws-smoke-temp` 工作区调用 `POST /api/documents/options` 后，会返回 `requestId=req_aef4159e-24f2-43a8-b168-864c4b2b2c6c`、`traceId=trace_3cbc114e-db01-410f-933c-e63d8bd83393`、`commandId=cmd_2cb6871d-9075-4252-b698-a7c4ea069bfd`，且后续 `/api/bridge/request` 与 `/api/bridge/trace` 已能回查到对应 `command_logs/domain_events`。本轮同时保留 `documents.meta` 读链最小验证：真实 `GET /api/documents/meta?documentId=...&workspaceId=ws-smoke-temp` 已返回 `doc + meta.requestId/traceId/queryName=documents.meta.get`。另外 `documents/stats` 写链的真实 HTTP smoke 也已完成并可回查。2026-04-14 新增一轮真实复测：同一 `documentId` 连续执行 `POST /api/documents/options {showToc:true,layoutDensity:\"compact\"}` 与 `POST /api/documents/stats {wordCount:12,characterCount:34,blockCount:2,todoTotal:5,todoDone:3}` 后，紧跟 5 次 `GET /api/documents/meta` 均稳定返回本次写入值，未再复现“同次写入后 meta 读回不稳定”的现象。为避免历史脏数据导致偶发漂移，已把 `convex/documents.ts` 的关键 `by_document_id` 读写收口到 deterministic canonical record 选择逻辑，并补了重复 business id 的回归测试。
  2026-04-14 第二批真实收口：已将仍直接依赖 `by_document_id.first()` 的高风险页面/文档关联路径继续切到同一 canonical document helper，当前已覆盖 `convex/documentShares.ts`、`convex/documentGroupShares.ts`、`convex/documentStars.ts`、`convex/comments.ts`、`convex/references.ts`。这批路径分别影响页面共享权限判定、群组公开、收藏可见性、评论线程读写与反链标题读取；此前若同一 business `documentId` 存在重复物理记录，会继续存在命中漂移风险。本轮已补跑目标文件 `eslint`、`src/lib/documents/document-record.test.ts`，并用源码扫描确认这批目标文件内已不再残留 `by_document_id.first()`；当前未继续扩到 `mediaAssets.ts`、`mindmaps.ts` 等非本批最小闭环路径。
  2026-04-14 第三批真实收口：继续只处理剩余 still-high-risk 的 `documents.by_document_id` 直接命中点，已新增 `convex/_utils/documentRecord.ts#getCanonicalParentDocumentId`，并把 `convex/comments.ts`、`convex/documents.ts` 中共享/权限祖先链扫描统一改到该 helper，避免同一 business `documentId` 的重复物理记录在父链遍历时再次漂移。同时已把 `convex/mindmaps.ts` 的 owner 校验从 `by_document_id.first()` 切到 `requireCanonicalOwnedDocument`，并将 `convex/mediaAssets.ts#createWithStorage` 的页面归属校验改为 `getCanonicalDocumentByBusinessId`，以覆盖页面内容附件上传这一仍会直接命中旧记录的高风险入口。本批最小验证目标为：补充 canonical helper 单测、对上述目标文件跑 `eslint`，并再次用源码扫描确认 `comments/documents/mindmaps/mediaAssets` 内不再残留直接依赖 `documents.by_document_id` 的实现。
  2026-04-14 第四批真实收口：按本轮 C1 要求只处理 `convex/documentStars.ts` 剩余两个父链祖先扫描点，已将 `resolveSharePermission` 与 `resolveGroupSharePermission` 中手写的 `documents.by_document_id` 父级推进统一改为 `getCanonicalParentDocumentId`。同时已补充 `src/lib/documents/document-record.test.ts` 的 helper 回归用例，验证重复 business `documentId` 下即使旧记录已删除，父链 helper 仍稳定返回 canonical 父页面 id；并已补跑目标文件 `eslint` 与 `vitest`。本轮源码扫描确认 `wolai-frontend/convex/` 业务路径中已不再残留直接 `withIndex(\"by_document_id\")` 命中点，当前仅剩 `convex/_utils/documentRecord.ts` 作为底层 canonical helper 持有该查询。

C1 验收：

- [x] 页面元信息至少已有 3 条低风险链路切入 Rust 层。
- [x] 文档页外观与交互未退化。
- [x] trace 字段已可回查到页面级写入：`documents.title.update`、`documents.stats.update`、`documents.options.update` 的真实 HTTP 写入均已返回 `requestId/traceId`，且后续 `/api/bridge/request` 与 `/api/bridge/trace` 已复核可查到对应 `command_logs/domain_events`。

  2026-04-14 C1 浏览器回归补记：已新增 `/mnt/Data1T/mnote/scripts/task019-document-ui-regression.js` 并在真实本地实例 `http://127.0.0.1:3001` 上执行。脚本会创建临时页面，确认 Sidebar 主导航与“私有 / 我的页面”分区可见、文档页标题输入框与 BlockNote 编辑区正常渲染，然后实际修改标题与正文，等待 `/api/documents/title`、`/api/documents/save` 成功返回并出现“已保存”，最后刷新页面确认标题与正文仍保留，再调用 `/api/documents/purge` 清理临时页面。实跑结果通过，说明本轮协议层切换后文档页主交互未退化。

### C2 Sidebar 聚合

- [x] 盘点 Sidebar 真实数据来源，锁定 `sidebar.tsx`、`private-tree.tsx`、`file-tree.tsx`、`use-convex-sidebar-data.ts`、`sidebar-tree.ts`。
- [x] 先把 Sidebar 的查询聚合逻辑抽象成 Rust query 目标，避免继续在前端和 API 中重复拼树。
- [x] 为 Sidebar 建立最小查询契约，至少覆盖页面列表、层级关系、文件树行模型和展开状态所需字段。
- [x] 保留现有 Sidebar UI 和交互，不引入第二套导航壳，也不从 `mnote-rust` 复制 `sidebar.tsx` 覆盖现实现。
- [x] 把 Mindmap、表格、媒体等派生资源的聚合边界整理成后续 Rust query 可接入的明确目标。

  2026-04-14 盘点补记：当前主入口已确认位于 `wolai-frontend/src/components/sidebar/sidebar.tsx`，私有树/文件树分别位于 `components/sidebar/private-tree.tsx` 与 `components/sidebar/file-tree.tsx`；数据侧同时存在 `/api/sidebar` 聚合 route、`hooks/use-convex-sidebar-data.ts` 实时订阅组装，以及 `lib/sidebar-tree.ts` 的树/section 构建逻辑，说明 C2 的真实起点是“API 聚合 + 前端二次拼装”的双层结构。
  2026-04-14 契约补记：当前最小 Rust query 目标已明确为兼容 `SidebarInitialData` 的单查询返回，至少覆盖 `active_workspace_id`、`workspaces`、`documents`、`trashed_documents`、`media_assets`、`trashed_media_assets`、`mindmap_assets`、`trashed_mindmap_assets`、`table_assets`、`trashed_table_assets`、`mindmap_docs`、`mindmap_asset_children`，从而先替换聚合来源而不改 `buildDocumentTree/buildVisibleRows` 的前端渲染逻辑。
  2026-04-14 边界补记：当前已明确必须保持不变的 UI/交互包括 `starred/public/shared/private/templates` 分区语义、`sort_order -> created_at` 排序口径、`doc/index.md/asset-folder/asset` 文件树行语义、拖拽/剪贴板协议，以及回收站双 tab 与资源计数行为；Mindmap、表格、媒体三类派生资源的聚合边界已被明确列为 Rust query 后续接入目标。
  2026-04-14 C2 第一刀收口补记：已新增 `wolai-frontend/src/lib/sidebar-data.ts` 与 `wolai-frontend/src/lib/server/sidebar-data.ts`，把 `src/app/(app)/layout.tsx`、`src/app/api/sidebar/route.ts`、`src/hooks/use-convex-sidebar-data.ts` 之间重复的 `SidebarInitialData` 组装统一收口到共享 helper；同时修复 hook 链路中 `mindmapAssetChildren` 长期为空的漂移，补充 `src/lib/sidebar-data.test.ts`，并通过 `pnpm test src/lib/sidebar-data.test.ts src/lib/file-tree/rows.test.ts` 与定向 `eslint` 验证。基于本轮复核，当前已可确认“多个前端位置不再重复拼装同一棵树”这一验收点达成；但由于 SidebarInitialData 仍未冻结为明确 Rust query contract，`C2` 其余验收项暂不提前勾选。
  2026-04-14 C2 第二刀补记：已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/process/sidebar-rust-query-target.md`，把 `sidebar.dataset.list` 的最小 payload/result、Rust query 与前端投影职责边界、以及“不复制第二套导航壳/不直接输出前端渲染树”的约束固定成文档。当前可确认 Sidebar 查询聚合目标已经从“散落在 route 和 hook 中的实现细节”收口为明确的 Rust query 接入目标。

C2 验收：

- [x] Sidebar 至少一条主查询已经改由 Rust query 供给。
- [x] 文档树、文件树、回收站等视图语义保持一致。
- [x] 不再需要在多个前端位置重复拼装同一棵树。

  2026-04-14 C2 第三刀补记：已新增 `wolai-frontend/convex/sidebar.ts`，把页面列表、回收站、Mindmap、媒体、表格等数据集收口成单个 `sidebar.datasetList` 主查询；`src/lib/server/sidebar-data.ts` 与 `src/hooks/use-convex-sidebar-data.ts` 均已切换为消费这条单查询返回，再通过既有 `SidebarInitialData` 投影层驱动 UI。配合 `src/lib/sidebar-data.test.ts` 的契约冻结、`src/lib/file-tree/rows.test.ts` 的文件树行语义验证，以及定向 `eslint`，当前可确认文档树、文件树、回收站双 tab 依旧沿用原有前端投影逻辑，没有因数据源切换而改变语义。
  2026-04-15 C2 第四刀补记：`/api/sidebar` 现已从“先直跑 Convex helper，再额外挂 meta”推进为真实 Rust query transport。当前 route 会先执行 `buildDocumentQueryEnvelope(name=\"sidebar.dataset.list\") -> resolveRustBridgeQueryPlan -> executeRustBridgeQueryTransport`，再把 `sidebar:datasetList` 的结果投影回 `SidebarInitialData`；这意味着 Sidebar API 主链已经真正进入 Rust runtime/bridge，而不再只是挂一个 envelope 名字。

### C3 BlockNote 正文保存

- [x] 盘点正文保存链路，锁定 `blocknote-editor.tsx`、`schema.ts`、文档保存 API 当前入口。
- [x] 先把正文保存切成“前端快照采集”和“Rust command 提交”两个边界。
- [x] 为正文保存定义最小协议对象，至少包含 `page_id`、`workspace_id`、`revision`、`actor`、`source`、block 快照、冲突检测字段。
- [x] 先接入低风险保存模式，例如显式保存或节流保存，不先处理复杂协同细节。
- [x] 确保正文链与页面元信息链、Sidebar 链共用同一 identity 口径，不再出现多套 page id 映射。

C3 验收：

- [x] 正文保存至少一条正式链路已经通过 Rust command 回写 Convex。
- [x] 保存失败时可返回稳定错误模型。
- [x] 保存成功时可回查 command log、domain event 与 trace。

  2026-04-14 C3 第一刀收口：已为 `documents.getContent` / `documents.save` 增加独立 `content_revision` 与 `content_conflict_key`，避免标题/统计信息更新污染正文 revision；`/api/documents/content` 现会透传 `revision/conflictDetectionKey`，`BlockNoteEditor` 会在自动保存时携带 `revision`、`conflictDetectionKey`、`snapshotCapturedAt`、`blockCount`，并在成功后刷新本地保存元数据。`save-command-adapter` 现把 Convex 冲突归一为 `409 REJECTED` bridge 错误，编辑器右上角也会展示保存失败信息。当前最小验证已补 `save-contract`/`bridge` 单测，并完成定向 eslint；结果为无 error，仅保留仓库既有 warnings。
  2026-04-14 C3 第二刀补记：源码复核确认 `BlockNoteEditor` 当前通过 `useDebouncedCallback(saveContent, 800)` 以防抖自动保存作为最小低风险保存模式，没有把复杂协同状态直接并入正文写链；同时 `documents.meta/title/stats/options/save` 这些 route 都把同一个 `normalizedDocumentId` 作为 `target.pageId`，`documents.content/save` payload 也统一使用 `documentId/workspaceId`，`sidebar.dataset.list` 则以同一 `workspace_id` 作用域返回 `documents[].id` 作为页面业务 id，因此当前正文链、页面元信息链与 Sidebar 聚合链已不存在第二套 page id 映射口径。
  2026-04-14 C3 第三刀补记：在此前真实 `/api/documents/save -> /api/bridge/request|trace` smoke 已确认可回查的基础上，本轮又补了 `src/lib/documents/bridge.test.ts` 的成功路径断言，明确 `executeSaveBridgeCommand` 在 revision/conflictDetectionKey 新协议下仍会调用 `recordBridgeCommandArtifacts`，并把同一 `requestId/traceId/commandId` 暴露给回查入口。因此当前“保存成功时可回查 command log、domain event 与 trace”已具备历史 HTTP smoke 与当前单测的双重闭环。
  2026-04-14 C3 第四刀补记：`save-command-adapter` 已进一步切到与页面元信息链一致的最小运行时接缝。当前 `documents.save` 会先构造 `functionName=documents:updateContent`、`payloadJson`、`args` 组成的 bridge mutation request，再由统一执行器实际调用 Convex；这让正文保存不再长期停留在“adapter 内直接手写 `client.mutation(...)`”的临时态，同时保留现有冲突归一和落账逻辑不变。
  2026-04-15 Phase 5 第一刀补记：`search.documents`、`search.recent` 已补齐到主仓 Rust query/runtime 主链。当前 `rust/crates/core-protocol` 新增 `SearchDocuments/SearchRecent`，`storage-convex-bridge` 与 `bridge-runtime` 已支持 query name -> Convex function 映射和运行时分发；`rust/crates/index-fts` 新增 `evaluate_search_documents`，负责标题/正文/思维导图/表格/附件的召回合并、排序、高亮 snippet 与 OCR 待补队列决策。`wolai-frontend/src/app/api/search/documents/route.ts` 现仅保留参数整理、原始数据装载与 HTTP 回传，不再持有 TS 侧的核心 ranking/snippet 逻辑；`/api/search/recent` 继续只承担最近访问写入 side-effect。

## 6. Phase D：Mindmap 与 OnlyOffice 边界接入

完成目标：

- 保留 `mnote` 当前成熟的 Mindmap 与 OnlyOffice 前端实现。
- 把数据边界、对象边界和回调边界逐步纳入 Rust adapter / protocol 规划，而不是复制第二套对象页壳。

Checklist：

- [x] 锁定 Mindmap 当前主组件和嵌入链路，确认 `MindmapBlock.tsx` 同时服务 BlockNote 内嵌块与独立全屏页。
- [x] 盘点 Mindmap 数据入口，锁定 `mindmapLocalStore.ts`、`mindmapOps.ts`、`app/api/mindmap/**`、`app/mindmap/**`。
- [x] 把 Mindmap 的前端交互状态与本体数据/ops 边界拆开，后者逐步映射到 Rust 协议层。
- [x] 明确 `mnote-rust/app/documents/[id]/mindmap/page.tsx` 等对象页壳不进入主仓主线。
- [x] 为 Mindmap 设计最小 adapter 目标，至少覆盖节点树、节点引用、节点操作日志和与 page/block 的绑定关系。
- [x] 锁定 OnlyOffice 当前页面和 API 边界，确认 `src/app/onlyoffice/`、`src/app/api/onlyoffice/**`、`src/components/onlyoffice/` 的职责分工。
- [x] 保留根目录 `src/components/onlyoffice/` 的静态资源、插件和数据目录，不做误删、不做迁移式替换。
- [x] 把 OnlyOffice 的对象解析、签名、callback、forcesave、代理请求边界整理成 Rust adapter 的明确目标。
- [x] 继续保持“正文只嵌文件入口，OnlyOffice 在独立页面运行”的产品形态。
- [x] 统一 Mindmap 与 OnlyOffice 的页面标识、附件标识、页面归属和追踪字段。

  2026-04-14 Phase D 盘点补记：已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/mindmap-onlyoffice-boundary.md`，固定 `MindmapBlock.tsx` 与独立全屏页共用同一核心组件、`mindmapLocalStore.ts`/`mindmapOps.ts`/`app/api/mindmap/**` 的数据与 ops 边界，以及 OnlyOffice 的 `page -> client -> sign/proxy/callback/forcesave` 职责分层。文档同时明确 `MediaBlock` 仅作为 Office 附件入口、`/onlyoffice` 继续作为独立编辑页面，且历史仓中的对象页壳与第二套 sidebar 只保留为参考实现。
  2026-04-14 Phase D 收口补记：已把 Mindmap API 与组件侧统一到与 OnlyOffice 对齐的业务标识口径。当前 Mindmap 统一使用 `pageId=documentId`、`attachmentId=mindmapId`、`workspaceId` 作为页面归属，并在 `/api/mindmap/**` 返回稳定的 `requestId/traceId` 元信息；OnlyOffice 继续使用 `documentId + assetId` 作为页面/附件标识，因此两条链后续接 Rust adapter 时不再需要第二套 page/attachment 映射。
  2026-04-14 Phase D 浏览器回归补记：已新增 `/mnt/Data1T/mnote/scripts/task021-mindmap-ui-regression.js` 并在真实本地实例 `http://127.0.0.1:3001` 上执行。脚本使用当前共享的 `MindmapBlockView` 全屏入口 `/mindmap/[docId]/[mindmapId]`，验证页面 `data-page-id/data-document-id/data-attachment-id/data-mindmap-id/data-workspace-id` 元信息、工具栏与“大纲”侧栏渲染、子节点新增与删除后的持久化、以及 `/api/mindmap/**` 返回的 `requestId/traceId` 会同步回 DOM。考虑到内嵌块与独立页共用同一核心组件，这轮浏览器回归可视为覆盖当前共享交互/保存内核，实跑未见退化。
  2026-04-15 Phase D OnlyOffice callback 收口补记：已为 `OnlyOffice callback` 新增最小命令 `media.assets.replace_storage`，同步补齐 `rust/crates/core-protocol` 的 `ReplaceMediaAssetStorage`、`rust/crates/storage-convex-bridge` 的 command name -> Convex mutation 映射，以及主仓 `buildDocumentBridgeMutationRequest` 的运行时接缝。`src/app/api/onlyoffice/callback/route.ts` 现保留下载文件、上传到 Convex Files 获得 `storageId` 的现有流程，但最终写回已改为经 `buildDocumentBridgeContextWithActor -> buildDocumentCommandEnvelope -> executeMediaAssetWritebackBridgeCommand` 进入统一 bridge 边界，再调用 `api.mediaAssets.replaceStorageFromUpload`。配套 `src/app/api/onlyoffice/callback/route.test.ts`、`src/lib/documents/bridge.test.ts`、Rust 单测与 `scripts/task022-onlyoffice-ui-regression.js` 已通过，确认 `storage_id` 在真实浏览器里继续发生变化。

Phase D 验收：

- [x] Mindmap 与 OnlyOffice 的前端界面仍以 `mnote` 当前实现为主，没有引入第二套主壳。
- [x] Mindmap 的节点/操作边界与 OnlyOffice 的签名/callback/forcesave 边界都已进入统一规划。
- [x] `src/components/onlyoffice/` 保持可用且未被误删。
- [x] `adapter-onlyoffice`、`adapter-mindmap` 仍作为后置实现项，而不是本阶段强行复制进主线。

## 7. Phase E：历史收口与单仓执行统一

完成目标：

- `mnote-rust` 正式退出主产品角色。
- `mnote` 主仓成为唯一启动、保存、规划和验证入口。

Checklist：

- [x] 统一团队口径：主产品仓只有 `/mnt/Data1T/mnote`，`/mnt/Data1T/mnote-rust` 只保留为历史参考和资产来源。
- [x] 把所有新的设计、执行清单、架构说明优先写入 `/mnt/Data1T/mnote/design/` 与 `/mnt/Data1T/mnote/rust/design/`。
- [x] 复查仓库脚本和说明文档，去掉“先进 `mnote-rust` 再启动”的旧叙事。
- [x] 统一根目录脚本入口，让仓库级脚本只从 `/mnt/Data1T/mnote/scripts/` 发起，再按需调用 `cargo --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml ...`。
- [x] 对仍需保留的 `mnote-rust` 资料按“核心规范 / 历史阶段 / 参考实现 / 错误方向”分类，避免后续误复制。
- [x] 把已确认不应主线保留的对象页壳、diagnostics 页、smoke 页继续留在历史仓，不进入主仓实现。
- [x] 对主仓内新增的 Rust 目录建立最小维护约定，明确谁负责 workspace、谁负责 bridge、谁负责接入链。
- [x] 重新审查 `ARCHITECTURE.md`、`AGENTS.md`、`rust-kernel-backport-plan.md` 与本 checklist，保证四者口径一致。
- [x] 固定“哪些目录默认不动”的硬边界，特别是 `wolai-frontend/`、`wolai-backend/`、`infra/convex/`、`src/components/onlyoffice/`。

Phase E 验收：

- [x] 后续协作默认只进入 `mnote` 主仓规划和开发。
- [x] 主仓文档和脚本不再把 `mnote-rust` 叙述为主执行入口。
- [x] 历史仓的保留范围、参考价值和禁止误复制范围都已固定下来。

  2026-04-14 Phase E 收口补记：已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-single-repo-maintenance-boundary.md`，统一记录主仓执行入口、历史仓资料分类、禁止误复制清单与 workspace/bridge/接入链责任面；同时已复查根 `package.json` 与 `scripts/desktop-hot.js`，确认仓库级脚本仍只从 `/mnt/Data1T/mnote/scripts/` 发起，且 `ARCHITECTURE.md` 已移除把 `mnote-rust` 写成未来执行承载面的表述。

## 8. 发布前总审计（跨阶段）

- [x] 为 `/mnt/Data1T/mnote/rust/` 补基础验证矩阵，至少覆盖 `cargo metadata`、`cargo check`、必要 crate 单测。
- [x] 为 bridge 入口补集成 smoke，验证最小查询、最小写入、日志生成、事件生成和错误返回。
- [x] 为文档页元信息、Sidebar、BlockNote 保存链补端到端回归，确认 UI 未因为协议层切换而退化。
- [x] 为 Mindmap 补交互回归，重点验证内嵌块、独立页、数据保存、节点操作和工具栏/侧栏行为。
- [x] 为 OnlyOffice 补回归，重点验证签名、代理、callback、forcesave、文档打开和静态资源可用性。
- [x] 检查主仓启动路径，确保开发者只需进入 `/mnt/Data1T/mnote` 就能完成前端、后端、Rust、OnlyOffice 相关联调。
- [x] 检查保存口径，确认页面、块、文档、索引的最终真相仍然落在 Convex，而不是被临时缓存目录劫持。
- [x] 检查 `trace_id`、`request_id`、`workspace_id`、`page_id` 在前端、bridge、Convex、日志中的一致性。
- [x] 对本次回迁引入的所有新目录和新文档做一次清点，确认没有误带入 `mnote-rust` 的历史噪音。
- [x] 为统一观测面补正式 Rust 能力面，至少包含 `bridge_request_get`、`bridge_trace_get`、`bridge_command_get`、`event_replay`、`index_rebuild` 这组 query/job/tool，并确认 Web 回查入口不再私有直连。

  2026-04-14 发布前审计补记：已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-backport-audit-inventory.md`，清点主仓 `rust/` 已并入的 workspace/crates/设计文档、本轮新增的根 `design/` 文档，以及当前仍未并入主线的 `adapter-*`、`mnote-cli`、`bridge/scripts/fixtures/tests` 目录。文档同时核对了 `package.json`、`scripts/desktop-hot.js` 与 `AGENTS.md` 的主仓启动口径，确认开发者只需进入 `/mnt/Data1T/mnote` 即可找到前端、后端、Rust 与 OnlyOffice 的联调入口。
- 2026-04-15 task-034 补记：已在 `rust/crates/core-protocol` 增补 `GetBridgeRequest/GetBridgeTrace/GetBridgeCommand` 以及 `bridge_request_get`、`bridge_trace_get`、`bridge_command_get`、`event_replay`、`index_rebuild` 五个统一观测/恢复工具；`rust/crates/storage-convex-bridge` 已补 query name -> Convex `bridgeLogs:*` 映射；`rust/crates/bridge-runtime` 已支持这组 query/job 的 plan/result 输出，并把 `index-fts::rebuild_from_events` 暴露为正式 `index_rebuild` 恢复入口。前端 `/api/bridge/request`、`/api/bridge/trace` 已切到 `buildDocumentQueryEnvelope -> resolveRustBridgeQueryPlan -> executeRustBridgeQueryTransport` 主链，同时支持按 `commandId` 过滤与统一排序返回；`src/lib/documents/bridge-log.ts` 也已把命令日志/领域事件状态显式化，为后续失败态、冲突态与补偿落账提供稳定边界。配套验证已通过全量 `cargo test --manifest-path rust/Cargo.toml` 与 bridge 定向 eslint。
- 2026-04-15 OnlyOffice 升级与实跑补记：已把 `8082` 文档服务从旧仓 `mnote-rust/infra/onlyoffice/docker-compose.yml` 迁回当前主仓 `/mnt/Data1T/mnote/infra/onlyoffice/docker-compose.yml`，并升级到 `onlyoffice/documentserver:9.3.1`。同时修复了 `/onlyoffice/plugins/*` 被 middleware 重定向到 `/auth` 导致自定义插件桥无法 ready 的问题，为 `wolai-frontend/public/onlyoffice/plugins/agent-tools/` 补齐非可视插件配置与 `plugins.js` 加载。最终 `scripts/task022-onlyoffice-ui-regression.js` 已在真实浏览器中通过，覆盖文档打开、`oo_insert_text` 插件调用、`同步保存`、callback 写回以及 `storage_id` 刷新变化闭环。
- 2026-04-15 OnlyOffice callback bridge 补记：本轮在复跑 `scripts/task022-onlyoffice-ui-regression.js` 前，曾因 `/auth` 快速登录触发 `POST /api/auth -> Could not find public function for 'auth:signIn'` 导致浏览器脚本卡在登录页；已通过 `cd /mnt/Data1T/mnote/wolai-frontend && pnpm exec convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping` 重新注册 Convex functions 后恢复。恢复后同一浏览器脚本再次通过，确认新接入的 `media.assets.replace_storage` bridge 命令没有破坏 OnlyOffice 打开、插件桥、forcesave、callback 与 `storage_id` 更新闭环。
- 2026-04-14 浏览器实跑补记：`task-019-document-ui-regression.js` 已在真实浏览器中覆盖“首页进入文档页 -> Sidebar 可见 -> 修改标题 -> 修改 BlockNote 正文 -> 等待保存成功 -> 刷新后仍保留”的最小闭环。运行前曾因本地 Convex 实例缺少 `workspaces:ensureDefaultWorkspace` 导致首页 `500`，本轮已通过 `pnpm exec convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping` 重新注册函数后恢复；最终浏览器脚本通过，且临时页面已清理。
- [x] 对以下禁止事项做最终复查：不双仓并行、不跨仓链接、不复制第二套产品前端壳、不把对象页壳/diagnostics/smoke 页带入主线、不散落多个 Rust 源码根。
- [x] 产出最终 cutover 文档，按能力域列清哪些 route 已仅剩 transport，哪些旧 TS 执行面必须继续迁移或后续删除。
- [ ] 以“单仓路径可启动、可保存、可验证、可继续演进”作为发布前收口标准。

  2026-04-14 实跑记录：已重新执行 `cargo metadata --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml --format-version 1`、`cargo check --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml`、`cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-domain`、`cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p core-protocol`、`cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p storage-convex-bridge`，均通过；其中 `cargo metadata` 已再次确认 workspace members 固定为 `core-domain`、`core-protocol`、`event-log`、`storage-convex-bridge`、`index-fts` 五个 crate。
  2026-04-14 源码审计补记：已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/release-readiness-source-audit.md`。该文档基于当前 route、adapter、Convex bridgeLogs 与定向测试，确认 bridge 入口已经覆盖最小查询/写入/日志/事件/错误返回闭环；确认正文、页面元信息、块补丁与 OnlyOffice 附件写回的最终真相仍然落在 Convex mutation；确认 `trace_id`、`request_id`、`workspace_id`、`page_id` 在 route、bridge、Convex 日志与回查入口之间使用统一口径；并完成“不双仓并行、不跨仓链接、不复制第二套前端壳、不把 diagnostics/smoke 页带入主线、不散落多个 Rust 源码根”的源码级复查。
  2026-04-15 task-035 补记：已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-cutover-v1.md`，把主仓当前 TS 执行面按 `RUST_OWNER / TS_TRANSPORT_KEEP / TS_COMPAT_PENDING / TS_LEGACY_DELETE` 四类状态完成盘点。文档明确了页面、块、查询聚合、AI、Mindmap、OnlyOffice 的当前归属，也明确了 `documents/create-child`、`documents/embed`、`documents/empty-trash`、`documents/purge`、`documents/template`、`mindmap-trash/empty`、`mindmap-ai/**` 与 `ai-agent` 非 Rust 核心工具面属于 Phase 8 前必须继续处理的旧面；同时为“何时允许宣布 Rust 成为唯一业务执行平面”补齐了四组 gate。
  2026-04-15 task-040/task-042/task-043/task-044 补记：AI 非 `doc_*` 核心工具中的 `search_web`、`image_read`、`slash_run` 已完成第一批 Rust Tool runtime cutover，`ai-agent/run` 不再保留这些工具的 TS 真执行兜底；`bridge-log/runtime` 已补齐统一失败态、冲突态与补偿态的第一批状态闭环，并覆盖页面主写链与 AI/Mindmap 写链；同时已新增 `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-legacy-delete-list.md`，把 `documents/create-child`、`documents/embed`、`documents/empty-trash`、`documents/purge`、`documents/template`、`mindmap-trash/empty`、`builtins/**` 固定为第一批 `TS_LEGACY_DELETE`。至此 Phase 8 的文档口径已经允许在源码审计层面使用“Rust 已成为 mnote 的唯一业务执行平面；Web route 只保留 transport、auth、session、streaming、proxy 与 callback 壳”这句统一结论。
