# [recycle] 发布前源代码审计

> 更新时间：2026-04-16
>
> 审计范围：`/mnt/Data1T/mnote`

## 1. Bridge 入口与日志回查

### 1.1 最小查询与写入入口

当前已确认的 bridge 主线入口：

- 查询：
  - `src/app/api/documents/content/route.ts`
  - `src/app/api/documents/meta/route.ts`
  - `src/app/api/sidebar/route.ts`
- 写入：
  - `src/app/api/documents/title/route.ts`
  - `src/app/api/documents/stats/route.ts`
  - `src/app/api/documents/options/route.ts`
  - `src/app/api/documents/save/route.ts`
  - `src/app/api/blocks/patch/route.ts`
  - `src/app/api/onlyoffice/callback/route.ts`

### 1.2 日志与事件落账

当前已确认：

- `src/lib/documents/metadata-command-adapter.ts` 成功路径会调用 `recordBridgeCommandArtifacts`
- `src/lib/documents/save-command-adapter.ts` 成功路径会调用 `recordBridgeCommandArtifacts`
- `src/app/api/blocks/patch/route.ts` 成功路径会调用 `recordBridgeCommandArtifacts`
- `src/lib/documents/media-asset-command-adapter.ts` 会在 ONLYOFFICE callback 成功写回后尝试复用同一 bridge log 落账
- `src/lib/documents/bridge-log.ts` 会同时写入：
  - `bridgeLogs.recordCommandLog`
  - `bridgeLogs.recordDomainEvent`
- 回查入口：
  - `src/app/api/bridge/request/route.ts -> bridgeLogs.listByRequest`
  - `src/app/api/bridge/trace/route.ts -> bridgeLogs.listByTrace`

结论：

- bridge 的最小查询、最小写入、日志生成、事件生成和错误返回已经形成源码闭环。

## 2. 保存口径审计

当前正文与页面元信息主写链如下：

- `documents.save -> api.documents.updateContent`
- `documents.title.update -> api.documents.updateTitle`
- `documents.stats.update -> api.documents.updateStats`
- `documents.options.update -> api.documents.updateOptions`
- `blocks.patch -> 读取文档内容后回写 api.documents.updateContent`

OnlyOffice 写回：

- `src/app/api/onlyoffice/callback/route.ts -> media.assets.replace_storage -> api.mediaAssets.replaceStorageFromUpload`

结论：

- 页面正文、页面元信息、块补丁与 OnlyOffice 附件写回最终都以 Convex mutation 为主事实写入点。
- 当前未发现把页面/块主真相改写到 `mnote-rust`、本地缓存目录或其他派生目录的主写链。

## 3. `trace_id` / `request_id` / `workspace_id` / `page_id` 一致性

### 3.1 前端与 route

- `buildDocumentBridgeContext()` 统一生成 `requestId`、`traceId`、`workspaceId`
- `buildDocumentBridgeContextWithActor()` 可为 ONLYOFFICE callback 这类无用户 cookie 的服务端回调显式注入 `actor/source`
- `buildDocumentCommandEnvelope()` 统一挂载 `commandId`、`target.pageId`
- `documents.title/stats/options/save` 均将 `normalizedDocumentId` 作为 `target.pageId`
- `onlyoffice/callback` 会把 `asset.document_id` 作为 `target.pageId`，并透传 `workspaceId`

### 3.2 日志落账

- `recordBridgeCommandArtifacts()` 使用同一 `context.requestId`、`context.traceId`
- `workspaceId` 统一取 `target.workspaceId` 或 `context.workspaceId`
- `targetPageId` 统一落到 command log
- domain event payload 同时记录 `request_id`、`trace_id`、`command_id`、`command_name`

### 3.3 当前辅助验证

- `src/lib/documents/bridge.test.ts` 已覆盖：
  - `target.pageId = doc_1`
  - `executeSaveBridgeCommand` 成功路径会调用 `recordBridgeCommandArtifacts`
  - 返回结果保留 `req_1`、`trace_1`
- `src/app/api/onlyoffice/callback/route.test.ts` 已覆盖：
  - callback 成功路径会调用 `executeMediaAssetWritebackBridgeCommand`
  - `storageId`、`assetId`、`documentId`、`workspaceId` 会进入 `media.assets.replace_storage` envelope

结论：

- `trace_id`、`request_id`、`workspace_id`、`page_id` 在 route、adapter、bridge log、回查入口之间已有统一口径。

## 4. 禁止事项复查

### 4.1 不双仓并行

- 主仓脚本与文档已统一指向 `/mnt/Data1T/mnote`
- `wolai-frontend/src`、`wolai-frontend/convex`、`rust/` 下未发现直接依赖 `/mnt/Data1T/mnote-rust` 的运行时代码路径

### 4.2 不跨仓链接

- 排除 `node_modules`、`.next`、`.venv`、`rust/target` 等构建产物后，主仓源码范围内未发现跨仓符号链接

### 4.3 不复制第二套产品前端壳

- 主仓保留的是既有 `wolai-frontend` 主壳
- 历史仓对象页壳与第二套 sidebar 仅在文档中被标记为禁止误复制范围

### 4.4 不把对象页壳 / diagnostics / smoke 页带入主线

- 当前主仓 `wolai-frontend/src/app` 下未发现新增的 `diagnostic` / `smoke` 页面目录
- 历史仓相关页面已在边界文档中明确列入禁止误复制清单

### 4.5 不散落多个 Rust 源码根

- 主仓顶层 `Cargo.toml` 仅存在 `rust/Cargo.toml`
- 其余 crate `Cargo.toml` 均位于 `rust/crates/*`

## 5. 运行态复核结果与最终结论

本审计只能关闭源码可验证项，但截至 2026-04-16，发布前运行态复核已经补齐五条直接证据：

- 已复跑 `scripts/task019-document-ui-regression.js`，文档页标题、正文、保存、刷新、回查链通过。
- 已复跑 `scripts/task021-mindmap-ui-regression.js`，Mindmap 全屏页的新增子节点、删除子节点、保存链、刷新回查与 `requestId/traceId` 元信息同步通过。
- 已复跑 `scripts/task022-onlyoffice-ui-regression.js`，ONLYOFFICE `9.3.1` 基线下的打开、插件桥、callback 写回、forcesave 与 `storage_id` 变化通过。
- 已通过 `pnpm exec vitest run src/lib/ai-agent/runtime/runAgent.test.ts`，补齐 `docs_search -> docs_read` 的 AI runtime 调用证据。
- 已通过 `bash /mnt/Data1T/mnote/rust/scripts/task049-cli-smoke.sh`，补齐 CLI 主链的最小真实执行验收。

当前已不再存在阻塞发布的 CLI / AI 运行态尾项。

补充核验结果：

- `cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -p bridge-runtime` 已通过。
- `wolai-frontend` 相关定向 `eslint` 当前无 error，仅剩仓库既有 warnings，不构成本轮发布阻塞。

仍然要求环境满足的前置条件：

- 浏览器回归环境可访问 `http://127.0.0.1:3000`
- `MNOTE_ONLYOFFICE_PROBE_DOCX=/tmp/mnote-onlyoffice-probe/probe.docx` 可用
- 已登录态可通过 `/auth` 或测试账号快速登录建立

## 6. 旧 TS 执行面割接清单

当前源码审计之外，还需要看“哪些 TS route 还能留，哪些只是历史兼容”。

本轮已新增：

- `/mnt/Data1T/mnote/design/old/08-legacy-rust-kernel/done/rust-kernel-cutover-v1.md`

该文档已把主仓当前执行面明确分成四类：

- `RUST_OWNER`
- `TS_TRANSPORT_KEEP`
- `TS_COMPAT_PENDING`
- `TS_LEGACY_DELETE`

其中当前仍需要长期观察但不再构成主链阻塞的旧面主要包括：

- `src/app/api/documents/embed/route.ts`
- `src/app/api/mindmap-ai/**`

其中页面旧面在 2026-04-16 的最终口径如下：

- `src/app/api/documents/create-child/route.ts` 已改走 `documents.create`
- `src/app/api/documents/empty-trash/route.ts` 已改走 `documents.emptyTrashByWorkspace`
- `src/app/api/documents/purge/route.ts` 已改走 `documents.purge`
- `src/app/api/documents/template/route.ts` 已改走 `documents.template`
- `src/app/api/documents/embed/route.ts` 已改走 `documents.save`，但目标页面插入位与 `pageReference` block 组装仍在 TS，因此继续按 `TS_COMPAT_PENDING` / 产品编排壳维护
- `src/app/api/mindmap/[docId]/route.ts` 与 `src/app/api/mindmap/[docId]/[mindmapId]/route.ts` 的 `DELETE/PATCH` 已改走 `mindmaps.delete/restore/purge`
- `src/app/api/mindmap-trash/empty/route.ts` 已改走 `mindmaps.emptyTrashByWorkspace`
- `src/app/api/blocks/*` 现网主链实际统一走 `src/lib/blocks/block-command-adapter.ts`；`src/lib/documents/block-command-adapter.ts` 应视为遗留兼容 helper，而非现网主执行面
- `src/app/api/ai-agent/run/route.ts` 的核心工具主链现在已经统一走 Rust tool runtime：`docs_search`、`docs_read`、`search_web`、`image_read`、`slash_run` 不再保留 TS 真执行兜底

结论：

- 当前可以说“Rust 已成为 mnote 的主业务执行平面”。
- 仍保留的 TS 路径只剩 `TS_TRANSPORT_KEEP`、少量 `TS_COMPAT_PENDING` 产品编排壳与冻结的 `TS_LEGACY_DELETE` 清单。
- 第一批 `TS_LEGACY_DELETE` 已不再阻塞这轮 release readiness；它们现在的要求是“保持纯壳 / 冻结 helper，不允许反向长出新的业务规则”。

最终 release readiness 口径：

- 若按源码审计口径：可以说明“Rust 已成为 mnote 的唯一业务执行平面”，同时明确仍保留 `TS_TRANSPORT_KEEP` 与少量产品编排壳。
- 若按完整发布口径：文档页、Mindmap、OnlyOffice、AI runtime、CLI smoke 的 Phase 8 scoped gate 已闭合，可以给出最终完成结论。
- 后续维护口径：剩余 `TS_TRANSPORT_KEEP` / `TS_LEGACY_DELETE` 只属于长期清理与边界维护，不再构成第二套业务执行平面。

补记：

- 2026-04-15 已复跑 `scripts/task019-document-ui-regression.js`，确认文档页标题、正文、保存与刷新回查通过。
- 2026-04-15 已复跑 `scripts/task021-mindmap-ui-regression.js`，确认新增/删除节点、保存链、刷新回查与 `requestId` / `traceId` 元信息同步通过。
- 2026-04-15 已复跑 `scripts/task022-onlyoffice-ui-regression.js`，在升级后的 ONLYOFFICE `9.3.1` 基线上确认 `oo_insert_text` 插件桥、`同步保存`、callback 写回与 `storage_id` 变化仍然通过；本次 callback 最终写回已不再由 route 直接调用 `api.mediaAssets.replaceStorageFromUpload`，而是先经 `media.assets.replace_storage` bridge 命令再落到 Convex。
- 2026-04-16 已通过 `src/lib/ai-agent/runtime/runAgent.test.ts`，确认 `docs_search -> docs_read` 的运行态工具链顺序、事件流与结果归一化闭合。
- 2026-04-16 已通过 `rust/scripts/task049-cli-smoke.sh`，确认 `sidebar/page/block/search/tool/mindmap` 主链 CLI 真实执行闭合。
