# Tree-First Graph Kernel Phase 3 专项任务拆分 v1 > 更新时间:2026-04-16 > > 关联文档: > - `/mnt/Data1T/mnote/design/tree-first-graph-kernel-checklist-v2.md` > - `/mnt/Data1T/mnote/design/tree-first-graph-kernel-v1.md` > - `/mnt/Data1T/mnote/design/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`:已完成 - Sidebar 服务端首包与 `/api/sidebar` 在配置 `MNOTE_WEB_BASE_URL` 后,会默认经 `/api/compat/next/sidebar` 走 `mnote-web` - `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` - 开关边界是 `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 主路径切换。**