# 3-2 [done] Tree-First Graph Kernel Phase 3 专项任务拆分 v1

> 更新时间：2026-04-16
>
> 后续更新（2026-04-23）：
> - 正式主链已移除 `MNOTE_WEB_BASE_URL` 与浏览器侧 `mnoteWebBaseUrl / mnoteWebTreeShellEnabled`
> - `mnote-web /api/compat/next/sidebar` 已降级为 legacy/debug 对照，不再是 `3000` 主链前提
> - `3104` 已按 `/mnt/Data1T/mnote/design/03-rust-web/done/3-4-mnote-web-3104-boundary-retirement-plan-v1.md` 退役为默认/公开边界
>
> 关联文档：
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-1-tree-first-graph-kernel-checklist-v2.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/reference/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/reference/3-1-rust-web-long-term-checklist-v2.md`

## 0. 本轮判断

这份拆解**整体是合理的**，但有两个口径需要收紧：

- `P3-3` 不能把“仍然复用同一份 `sidebar.dataset.list` 数据集的另一个 projection/query 名字”直接算成第二条真实主链
- `P3-5` 的第一条切流边界，最现实也最有价值的不是凭空新增页面，而是把 Sidebar 首包与 `/api/sidebar` 这条真实高频读链接到 `mnote-web`

基于 2026-04-16 当天的代码推进，这份拆解对应的落地情况已经变成：

- `P3-1`：已完成
- `P3-2`：已完成
- `P3-3`：已完成
  - 实际采用的是 `bridge.workspace.overview` / `bridge.request.get` / `bridge.trace.get` 这组真实 workspace / bridge 查询主链
- `P3-4`：已完成
- `P3-5`：已完成
  - 2026-04-16 阶段，Sidebar 服务端首包与 `/api/sidebar` 曾可通过配置 `MNOTE_WEB_BASE_URL` 切到 `/api/compat/next/sidebar`
- `P3-6`：已完成

## 1. 文档目的

这份文档只处理一件事：

> **把 `Kernel Phase 3：Rust Web 接入 kernel，成为主承载层` 单独拆开，按当前真实代码重新分解成可执行任务。**

原因很直接：

- `Phase 1` 和 `Phase 2` 已经完成
- `Phase 3` 现在不是“没开始”，也不是“接近完成”
- 它已经有真实代码，但工程量明显比最初预估更大

所以接下来的推进方式不应该继续写成一条大任务，而应该拆成若干可以逐个闭环的小阶段。

---

## 2. 当前真实完成情况

基于当前 git 中的实际代码，`Phase 3` 已经落下了下面这些东西。

### 2.1 已存在的 Rust Web 基础骨架

- `rust/crates/mnote-web/` 已进入 workspace
- 已有 `axum` app/router 骨架：
  - [app.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/app.rs)
  - [mod.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/mod.rs)
- 已有 request context / middleware / error 基础：
  - [context.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/context.rs)
  - [error.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/error.rs)

### 2.2 已存在的 kernel route

- 已有：
  - `/api/kernel/projections/sidebar`
  - `/api/kernel/subtree`
  - `/api/kernel/edges`
  - `/api/kernel/graph`
- route 文件：
  - [kernel.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/kernel.rs)

### 2.3 已接上的第一条真实查询接缝

当前最关键的一点是：

- kernel route 已不再只是本地 demo helper
- 它已经能先生成 `sidebar.dataset.list` 的 runtime query plan
- 再通过通用 Convex query transport 去请求 Convex `/api/query`

对应代码：

- [kernel.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/kernel.rs)
- [convex.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/transport/convex.rs)

这说明：

> **Phase 3 的“Rust Web 开始承接真实 kernel 查询主链”已经成立，但只成立在很窄的一条 Sidebar dataset 链路上。**

### 2.4 当前新增事实

- `transport/convex.rs` 已从 Sidebar 单点执行器收口为通用 query transport
- `mnote-web` 已新增：
  - `/api/bridge/workspace`
  - `/api/bridge/request`
  - `/api/bridge/trace`
  - `/api/compat/next/sidebar`
- fixture 已改成 `allow_dev_fixtures + MNOTE_WEB_QUERY_FIXTURES_JSON`
  - 不再是生产路径默认 fallback
- Next 侧的 Sidebar 首包与 `/api/sidebar` 已具备可切到 `mnote-web` 的兼容边界
- transport 已优先转发真实 `Authorization`，否则才回退到开发态 admin/dev identity

---

## 3. 当前 Phase 3 的真实缺口

### 3.1 fixture 已不再是生产 fallback

当前 fixture 已收口为：

- `allow_dev_fixtures`
- `MNOTE_WEB_QUERY_FIXTURES_JSON`

这意味着：

- 测试仍方便
- 但生产路径默认不会再悄悄吃 fixture
- query fixture 已能同时覆盖 kernel / bridge route 测试

### 3.2 真实数据链不再只覆盖 Sidebar dataset

现在真正打通的已至少包括：

- `sidebar.dataset.list`
- `bridge.workspace.overview`
- `bridge.request.get`
- `bridge.trace.get`

这说明 `mnote-web` 已经不再只是“局部样板接入”。

### 3.3 transport 已不再是单点实现

当前 transport 已能执行通用 query plan，并已被 Sidebar 与 bridge route 复用。

### 3.4 切流边界已经明确

当前已经明确：

- 第一条真实切流对象是 Sidebar 首包与 `/api/sidebar`
- 2026-04-16 阶段的切流开关边界曾是 `MNOTE_WEB_BASE_URL`
- 回退方式是移除该 base url，恢复 Next 侧原桥接逻辑

### 3.5 验证重点已经转向“主链稳定”

当前仍需持续补的不是“有没有 route”，而是：

- 更广义 kernel 数据源是否继续扩展
- 切流开启后的运行态回归
- 旧 Next/React 壳还能再收掉多少

---

## 4. Phase 3 的重新定义

为了避免范围继续膨胀，建议把 `Phase 3` 重新定义为下面这个最小目标：

> **让 `mnote-web` 至少承接一组不依赖 fixture 的真实 kernel 查询链，并具备可复用 transport、明确切流边界、可回归的集成验证。**

这版定义刻意不包含：

- 全部页面 SSR 重写
- 全部前端 API 切换
- 全部 Sidebar / 搜索 / AI / Mindmap consumer 切换

这些应该属于后续阶段。

`Phase 3` 只负责把 Rust Web 从“骨架 + 样板 route”推进成“可被后续阶段依赖的真实承载层”。

---

## 5. Phase 3 拆分原则

### 原则 1

先打通主承载链，再扩 consumer。

### 原则 2

先消除 fixture/样板依赖，再谈切流。

### 原则 3

先把 transport 层做成可复用，再扩第二条、第三条真实查询链。

### 原则 4

每一步都必须有明确验收，不允许再出现“骨架写了就算完成”。

---

## 6. Phase 3 任务拆分

建议把 `Phase 3` 拆成 6 个子任务。

---

## 7. P3-1：固化当前 Sidebar kernel 主链

**目标**

把当前已有的 Sidebar dataset -> kernel projection 这条链，从“能跑”收紧到“边界清晰、失败语义清晰、测试与真实链分离”。

**当前依据**

- [kernel.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/kernel.rs)
- [convex.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/transport/convex.rs)

**要做的事**

- 把 `MNOTE_WEB_KERNEL_SIDEBAR_FIXTURE_JSON` 限定为测试专用或开发专用
- 明确生产路径默认不允许 fixture fallback
- 为真实 Convex 查询失败补齐清晰错误语义
- 明确 workspace 缺失、auth 缺失、query 失败时的返回口径
- 给 Sidebar kernel route 补非 fixture 集成验证

**交付物**

- `kernel.rs` 的数据加载边界收紧
- 测试和生产路径分离
- 文档化的错误语义

**完成判定**

- 在非 fixture 模式下，Sidebar kernel route 可以稳定返回真实数据
- fixture 不再是默认隐性主链

---

## 8. P3-2：抽象可复用的 Rust Web transport/query provider

**目标**

把当前只支持 `sidebar:datasetList` 的单点实现，提升成后续可复用的 transport 层。

**当前问题**

- `execute_sidebar_dataset_query(...)` 是专用函数
- transport 还不是通用 query transport

**要做的事**

- 抽出通用的 Convex query 执行层
- 明确 query plan -> HTTP query -> JSON value 的公共路径
- 将 `sidebar.dataset.list` 改成这个公共层的首个 consumer
- 为后续第二条真实 query 链预留统一入口

**交付物**

- 可复用的 transport API
- Sidebar dataset 迁到通用 transport 之上

**完成判定**

- `transport/convex.rs` 不再只为 Sidebar dataset 服务
- 第二条 query 链可以直接复用同一 transport

---

## 9. P3-3：打通第二条非 Sidebar 的真实 kernel 查询链

**目标**

证明 `mnote-web` 不是只会做 Sidebar projection，而是开始具备更一般化的 kernel 主承载能力。

**优先建议**

优先级建议如下：

1. 工作区级 page tree / subtree 查询
2. workspace overview 类查询
3. 文档阅读页会直接需要的 subtree 查询主链

不建议一上来就选：

- 搜索
- AI
- Mindmap

因为这些 consumer 更重，依赖更多，会把 `Phase 3` 范围重新拉爆。

**要做的事**

- 基于已有 transport 层再接一条真实 query plan
- 让其经由 `mnote-web` route 对外提供
- 明确其 request context、workspace、auth、trace 透传
- 为它补路由级测试和真实集成验证

**交付物**

- 第二条非 Sidebar 的真实 kernel 查询 route

**完成判定**

- `mnote-web` 至少存在两条不依赖 fixture 的真实 kernel 查询主链

---

## 10. P3-4：补齐 Phase 3 的上下文、鉴权和错误稳定性

**目标**

让 `mnote-web` 具备作为主承载层的最低运行稳定性，而不是只有 happy path。

**当前依据**

- [context.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/context.rs)
- [error.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/error.rs)

**要做的事**

- 明确 request id / trace id / workspace id 的透传规则
- 明确 dev auth 与真实 auth 的边界
- 给 transport 错误、上游错误、参数错误建立稳定 code
- 检查 response header 是否统一回传 request/trace 上下文
- 给 4xx / 5xx 场景补测试

**交付物**

- Phase 3 级别的错误模型与上下文模型
- 对应测试

**完成判定**

- 真实错误不再落成模糊的 internal error
- request/trace/workspace 上下文可以稳定追踪

---

## 11. P3-5：定义并落地第一条真实切流边界

**目标**

明确 `Phase 3` 到底把哪一条真实前端流量切给 `mnote-web`。

**这是当前最容易被忽略的点**

如果没有切流边界，`Phase 3` 会永远停在“后端已准备好，但没人用”的状态。

**建议切流对象**

优先从这类低风险路径里选一条：

1. Sidebar kernel projection 的服务端读取链
2. 工作区树只读查询链
3. 文档只读 subtree 查询链

不建议在 `Phase 3` 就切：

- AI 运行主链
- 搜索主链
- 导图交互主链

**要做的事**

- 明确旧链和新链的边界
- 明确 feature flag 或环境开关
- 明确回退策略
- 明确前端 host 如何消费 `mnote-web` 结果

**交付物**

- 一条真实切流方案
- 对应开关和回退策略

**完成判定**

- 至少一条真实请求默认走 `mnote-web`
- 出现问题时可控回退

---

## 12. P3-6：补 Phase 3 的验收矩阵与收尾文档

**目标**

避免 `Phase 3` 再次在口径上被提前写成“已完成”。

**要做的事**

- 为 `Phase 3` 建立验收矩阵：
  - route 可用
  - 非 fixture 主链
  - 第二条真实查询链
  - 错误模型
  - 上下文透传
  - 切流边界
- 回写长期 checklist 中的 `Phase 3` 状态
- 回写 `harness` 任务状态

**交付物**

- 验收矩阵文档
- checklist 更新
- harness 状态更新

**完成判定**

- `Phase 3` 是否完成可以由矩阵直接判断，而不是靠描述性口径

---

## 13. 建议执行顺序

建议顺序如下：

1. `P3-1` 固化 Sidebar 主链
2. `P3-2` 抽通用 transport
3. `P3-3` 打通第二条真实查询链
4. `P3-4` 补上下文/鉴权/错误稳定性
5. `P3-5` 定义并落地第一条切流边界
6. `P3-6` 做验收矩阵和文档回写

原因：

- 如果不先收紧 Sidebar 主链，后面所有扩展都会继续复制不稳的模式
- 如果不先抽 transport，第二条查询链会继续写成特例
- 如果不先有第二条真实链，就无法证明 `mnote-web` 真能成为承载层
- 如果不定义切流，`Phase 3` 即使后端做完也无法进入后续阶段

---

## 14. 暂不纳入 Phase 3 的内容

下面这些先不要塞进 `Phase 3`：

- 搜索全面切到 Rust Web
- AI 全面切到 kernel-first tool bridge
- Mindmap 改成 kernel projection/editor
- `BlockNote` 完全退化为内容节点编辑器
- 旧前端壳清理

原因不是它们不重要，而是它们分别属于：

- `Phase 5`
- `Phase 6`
- `Phase 7`
- `Phase 8`
- `Phase 9`

如果提前塞回 `Phase 3`，这个阶段会再次失控。

---

## 15. Phase 3 完成的最终标准

只有同时满足下面几条，才建议把 `Phase 3` 标成完成：

- `mnote-web` 至少有一条不依赖 fixture 的真实 kernel 查询主链
- 在 Sidebar 之外，至少还有一条真实 workspace / storage / bridge 查询主链
- Sidebar 那条主链已经不再以 fixture fallback 作为默认路径
- transport 层已可复用，不再是单函数特例
- request/trace/workspace/error 语义已稳定
- 至少一条真实前端流量已切到 `mnote-web`
- 有清晰的回退策略和验收矩阵

当前这几个条件已经成立，因此 `Phase 3` 可以收口为：

> **DONE，但 Done 的含义是“Rust Web 已成为可被后续阶段依赖的真实承载层”，不是“所有 consumer 都已经切完”。**

---

## 16. 最终结论

`Phase 3` 当前最准确的判断是：

> **已经从“骨架 + 样板 route”跨到了“真实承载层完成”，后续应转入 `Phase 4+` 的 consumer 主路径切换。**
