# Rust Kernel / Web 实现偏差审查

> 执行状态：已归档到 `design/10-review/done/`。本文保留为历史审查快照，当前活跃口径以 `./06-execution-checklist-and-acceptance.md` 为准。

## 范围

本次只审查 Rust kernel / protocol / bridge-runtime / mnote-web / storage-convex-bridge 与当前设计主线的一致性。

重点对照设计：

- `ARCHITECTURE.md`
- `design/01-05-current-priority-overview.md`
- `design/01-tree-first-graph-kernel/reference/1-tree-first-graph-kernel-v1.md`
- `design/01-tree-first-graph-kernel/reference/1-1-tree-first-graph-kernel-checklist-v2.md`
- `design/02-convex-rust-long-term-architecture/process/2-tree-first-graph-convex-rust-long-term-architecture-v1.md`
- `design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
- `design/03-rust-web/reference/3-1-rust-web-long-term-checklist-v2.md`
- `design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md`
- `design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md`
- `design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md`

重点代码：

- `rust/crates/core-protocol/`
- `rust/crates/core-domain/`
- `rust/crates/bridge-runtime/`
- `rust/crates/mnote-web/`
- `rust/crates/storage-convex-bridge/`

## 结论

Rust kernel / protocol / bridge-runtime / mnote-web 的主干方向与当前设计基本一致：`core-protocol` 已有统一 kernel node / edge / projection / page aggregate 协议；`bridge-runtime` 已能执行 kernel query / command / projection；`mnote-web` 已持有 3000 主入口、文档页 shell、`/api/page-aggregate/:id`、tree command、`/api/tree/events`、Search shell 等关键接缝；`storage-convex-bridge` 明确把 `tree.*` / `page.*` 等语义命令映射到底层 Convex mutation。

主要偏差不是“Rust 主线没有落地”，而是当前仍存在几类收口缺口：

1. 部分 Rust Web 主路径仍会静默合成 fallback / fixture 数据，和 `Runtime Fallback 退场` 的激进口径不完全一致。
2. Page Aggregate 对外标记为 `KernelProjection`，但 Rust Web 仍先取 `documents.meta/content` 再在 runtime 内拼成聚合；这是合理过渡实现，但“单一 kernel 真源”口径容易被写得过满。
3. Tree realtime 已有正式 SSE 主链，但实现仍偏轮询 bridge overview，WS 仍是 snapshot/resync 骨架，尚未成为完整实时主链。
4. Legacy / compat 能力默认大多关闭，但配置位、proxy 辅助函数和兼容源枚举仍在，设计文档中“全部退场”的勾选状态可能偏乐观。

## 关键发现表格

| 编号 | 分类 | 严重度 | 发现 | 证据 |
| --- | --- | --- | --- | --- |
| RK-01 | 未完成 | 中 | Kernel projection 仍主要从 `sidebar.dataset.list` 这一份 Convex 数据集构建，广义 node pool / reference edge / summary/index 真相层尚未完全独立。 | `rust/crates/mnote-web/src/routes/snapshot_support.rs:27` 定义 `sidebar.dataset.list`；`:93` 先加载 sidebar dataset 再执行 `kernel.project_view`；`rust/crates/bridge-runtime/src/lib.rs:8010` 后续由 sidebar 数据构建 subtree；`:8111` 再转为 projection。 |
| RK-02 | 实现偏差 / 风险 | 高 | Rust Web 主路径仍存在静默 fallback：workspace shell 在 projection 加载失败时无条件合成最小 workspace/documents；sidebar/filetree 在 `allow_dev_fixtures` 时合成开发数据；Search 在 Convex query 失败时返回内置搜索数据。这与 `3-15-runtime-fallback-retirement` 的“默认不再 fallback”口径冲突。 | `rust/crates/mnote-web/src/routes/web_shell.rs:2379` 到 `:2401` 无条件 fallback 最小 dataset；`:2432` 到 `:2461` 合成 sidebar dev dataset；`:2493` 到 `:2519` 合成 filetree dev dataset；`rust/crates/mnote-web/src/routes/search.rs:233` 到 `:247` 搜索失败后走 `fallback_search_dataset`。 |
| RK-03 | 方向变化 / 文档滞后 | 中 | Page Aggregate 已由 Rust Web 暴露正式 route，但实现仍是先读 `documents.meta/content`，再把 joined data 交给 `page.aggregate.get` 生成 projection。代码对外 source 标成 `KernelProjection`，但底层仍是 meta/content join 的迁移形态；需要文档明确这是 Rust runtime adapter，而非完整 kernel storage 真源。 | `rust/crates/mnote-web/src/routes/web_shell.rs:2282` 到 `:2315` 先读 meta/content 再执行 `page.aggregate.get`；`rust/crates/bridge-runtime/src/lib.rs:8246` 到 `:8253` 将 source 传为 `PageAggregateSource::KernelProjection`；`:5303` 到 `:5324` 从 meta/content 中抽取 title/content/revision。 |
| RK-04 | 未完成 | 中 | Tree realtime 正式 route 已存在，但当前 SSE 仍通过 polling `bridge.workspace.overview` 生成 snapshot/delta/resync；WS 只发送初始 snapshot，并只支持客户端请求 resync，不是完整主实时链路。 | `rust/crates/mnote-web/src/routes/sse.rs:51` 到 `:91` 循环 sleep/poll overview 后生成 delta；`rust/crates/mnote-web/src/routes/ws.rs:32` 发送 snapshot，`:40` 到 `:80` 只处理 resync 或 unsupported ack。 |
| RK-05 | 风险 / 文档滞后 | 低 | Legacy Next compat 默认关闭，但代码仍保留 env-gated proxy 能力、Next proxy 辅助函数和 compat 配置位。若文档继续写“legacy compat 已删除”，会与代码事实不一致；若保留，应写成显式调试/迁移边界。 | `rust/crates/mnote-web/src/app.rs:42` 到 `:54` 仍读取 `MNOTE_WEB_LEGACY_NEXT_BASE_URL` / `MNOTE_WEB_ENABLE_LEGACY_NEXT_COMPAT`；`rust/crates/mnote-web/src/routes/gateway.rs:86` 到 `:87` auth API 可转 legacy proxy；`:402` 到 `:499` legacy proxy 实现仍在；`rust/crates/mnote-web/src/routes/documents.rs:153` 当前 `should_proxy_via_next` 返回 false，但 Next proxy helper 仍保留。 |
| RK-06 | 实现一致 | 低 | Tree command cutover Stage 2 的长期命名面已在 Rust route / bridge / storage mapping 中落地，`documents.*` 仍作为 alias/底层 Convex mutation 名称存在，和 Stage 2A/2B 过渡口径基本一致。 | `rust/crates/storage-convex-bridge/src/mapping.rs:37` 到 `:43` 映射 `tree.*`；`:52` 到 `:68` 保留 `documents.*` / `page.*` alias；`rust/crates/mnote-web/src/tree_shell/dispatcher.rs:16` 到 `:23` 使用 `tree.*`；`rust/crates/mnote-web/src/routes/tree.rs:7634` 附近测试确认 documents alias 映射仍存在。 |
| RK-07 | 实现一致 | 低 | Debug shell 默认关闭，符合 `3104`/debug 壳默认退场口径。 | `rust/crates/mnote-web/src/routes/mod.rs:120` 到 `:124` 仅在 `enable_debug_shell_routes` 时挂 `/tree` 和 `/document-debug`；同文件测试 `:142` 到 `:184` 验证默认 404。 |

## 证据

### 1. Kernel / projection 已落地，但底层仍主要基于 sidebar dataset

- `rust/crates/core-protocol/src/kernel.rs:7` 到 `:42` 定义 `KernelNodeType`、`KernelEdgeType`、`KernelProjectionKind`。
- `rust/crates/mnote-web/src/routes/kernel.rs:62` 到 `:85` 暴露 projection route，并经 `load_projection_snapshot` 获取投影。
- `rust/crates/mnote-web/src/routes/snapshot_support.rs:27` 到 `:47` 固定 `sidebar.dataset.list` 为数据获取入口。
- `rust/crates/bridge-runtime/src/lib.rs:8119` 到 `:8137` 在没有 root 时由当前数据构建 subtree，再生成 projection；`file_tree` 另走 `build_file_tree_projection_result`。

判断：这符合 `1-1` 中“真实主线已落地，但更广义 node pool/reference edge 仍后续”的口径，不应被写成“尚未开始”；也不应被写成“完整 kernel 真源已闭环”。

### 2. Runtime fallback 仍在主路径附近

- `rust/crates/mnote-web/src/routes/web_shell.rs:2379` 到 `:2401`：workspace shell projection 加载失败时合成 `active_workspace_id`、`workspaces`、`documents`。
- `rust/crates/mnote-web/src/routes/web_shell.rs:2432` 到 `:2461`：`allow_dev_fixtures` 时合成 sidebar dev dataset。
- `rust/crates/mnote-web/src/routes/web_shell.rs:2493` 到 `:2519`：`allow_dev_fixtures` 时合成 filetree dev dataset。
- `rust/crates/mnote-web/src/routes/search.rs:233` 到 `:247`：搜索 Convex 查询失败后执行 `fallback_search_dataset(workspace_id)`。

判断：这与 `design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md` 的“默认运行时不再 fallback / 不静默降级”存在偏差。尤其 Search fallback 会产生看似真实的固定结果，风险高于空状态降级。

### 3. Page Aggregate 是 Rust route，但仍是迁移期 adapter

- `rust/crates/mnote-web/src/routes/mod.rs:53` 到 `:56` 挂载 `/api/page-aggregate/{document_id}`。
- `rust/crates/mnote-web/src/routes/web_shell.rs:2264` 到 `:2319` 构建 aggregate。
- `rust/crates/bridge-runtime/src/lib.rs:5291` 到 `:5442` 从 meta/content 形状构建 `PageAggregateProjection`。
- `rust/crates/core-protocol/src/page_aggregate.rs:4` 到 `:10` 协议层仍保留 `KernelProjection`、`CompatMetaContentJoin`、`Fixture` 三种 source。
- `rust/crates/mnote-web/src/page_aggregate/builder.rs:66` 默认 source 仍是 `CompatMetaContentJoin`，但当前检索未发现该 builder 进入主要 route 主路径。

判断：当前代码已摆脱 TS builder runtime 主链，但还不是“页面域全部直接来自独立 kernel storage 真源”。文档应保留“Rust-first Page Aggregate 过渡态”的精确口径。

### 4. Tree realtime 主链已成立，但不是完整实时闭环

- `rust/crates/mnote-web/src/routes/mod.rs:113` 挂载 `/api/tree/events`，`:114` 挂载 `/api/stream/events`，`:115` 挂载 `/api/realtime/ws`。
- `rust/crates/mnote-web/src/routes/sse.rs:127` 到 `:146` 给 `/api/tree/events` 打 `x-mnote-web-owner: mnote-web` 与 `x-mnote-tree-stream-owner: rust-web`。
- `rust/crates/mnote-web/src/routes/sse.rs:51` 到 `:91` 通过 sleep/poll bridge overview 发现变化。
- `rust/crates/mnote-web/src/routes/ws.rs:32` 到 `:80` WebSocket 当前只发 snapshot，并响应 resync 请求。

判断：这与 `3-3` 中“已完成 route / snapshot / delta / resync 基础，WS 尚未成为主链，live cache 未完全统一”一致；若 `3-15` 写成 tree realtime 补偿链已完全删除，则偏乐观。

### 5. Compat / legacy 未成为默认主链，但未完全删除

- `rust/crates/mnote-web/src/app.rs:42` 到 `:54` 仍读取 legacy Next 相关环境变量，默认 `enable_legacy_next_compat` 为 false。
- `rust/crates/mnote-web/src/routes/gateway.rs:86` 到 `:87` 在 compat 开启且配置 legacy base URL 时，`/api/auth` 可走 legacy proxy。
- `rust/crates/mnote-web/src/routes/documents.rs:153` 当前 `should_proxy_via_next` 返回 false，说明文档 API 默认不走 Next proxy。

判断：代码实际状态更像“默认关闭、残留显式迁移/调试能力”，不是“所有 legacy proxy 代码已删除”。

## 建议优先级

### P0

- 移除或显式隔离 Search 的 `fallback_search_dataset`。失败时应返回明确错误或空 projection，并带可观测错误头；不要返回固定假结果。
- 对 `load_workspace_shell_projection` 的无条件合成 dataset 做决策：若用于首屏容错，应在响应或 contract 中显式标记 degraded；若严格执行 fallback 退场，应改为失败或空树，不再伪装成真实 workspace projection。

### P1

- 将 `allow_dev_fixtures` 相关 fallback 全部加上更明确的 debug/dev 标识，并确认 `desktop:hot` / 3000 默认启动链不会误开。
- 补一条 Rust Web smoke：Convex/query 不可用时，搜索、Sidebar、filetree 不应返回假业务数据。
- Page Aggregate 文档补一句：当前 Rust route 已是主读链，但底层仍通过 Rust runtime adapter 消费 meta/content substrate；完整页面域单一真源仍在推进。

### P2

- Tree realtime 后续应把 SSE polling overview 与真正 domain event stream 的边界写清楚，并继续推进 page subtree / filetree / preferred snapshot 同一 live cache。
- Legacy Next proxy 若仍需保留，建议统一命名为 explicit migration/debug boundary；若不再需要，后续单独删除 proxy helper、配置位和测试样例，避免和 `3-15` 的退场状态长期冲突。
- `PageAggregateSource::CompatMetaContentJoin` / `Fixture` 是否继续保留在 `core-protocol` 需要架构决策：保留则标记为迁移态 source；删除则需先确认没有测试、local folder、fixture 依赖。

## 修改的文件路径

- `/mnt/Data1T/mnote/design/10-review/done/01-rust-kernel-web-review.md`
