docs: codify fallback retirement direction

This commit is contained in:
lix-2026
2026-05-10 08:46:43 +08:00
parent b7ceb7afae
commit 2f9ef85350
16 changed files with 616 additions and 63 deletions
@@ -0,0 +1,155 @@
# 3-15 [process] Runtime Fallback 退场 Checklist v1
> 更新时间:2026-05-09
>
> 关联:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-1-rust-web-long-term-checklist-v2.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md`
## 1. 目标
这份 checklist 只回答一件事:
> **把已经不该继续充当系统组件的 runtime fallback、compat、legacy 与对照链,尽快退出主路径。**
本轮采用激进退场口径:
- 能退场的先退场
- 退场对象同时退出运行时、默认入口与活跃设计口径
- `/mnt/Data1T/mnote/recycle` 只保留参考物,不再参与系统主路径
## 2. 主路径白名单
下面这些属于必须保活的主路径:
- [x] 文档页打开链继续可用
- [x] Sidebar 继续可用
- [x] `/api/tree/events` realtime 主链继续可用
- [x] 页面标题保存继续可用
- [x] 页面设置保存继续可用
- [x] 正文保存继续可用
下面这些不再享有默认兼容资格,可直接进入退场名单:
- [x] `BlockNote` fallback / 对照链
- [x] AI provider 直连分支(`Hermes` / `Codex` / 旧 orchestrator compat
- [x] legacy Next compat / alias / debug 壳
- [x] TS page aggregate builder fallback
- [x] 仍以旧 owner / 旧 fallback 作为默认系统组件的活跃文档表述
## 3. 总原则
- [x] 不再把“开发态”作为保留 fallback 的理由
- [x] 不再把“以后可能参考”作为继续挂在主路径上的理由
- [x] 凡移入 `recycle/` 的对象,都必须先断开主路径 import / route / fallback 选择
- [x] 主路径缺口优先补 Rust-first 正式链,不恢复 legacy fallback
- [x] 次要入口允许直接 404 / 410 / 501,不再静默降级
## 4. 第一波:立即退场
### 4.1 `BlockNote` fallback / 对照链
- [x] 删除页面壳里“显式切回 BlockNote”的默认入口
- [x] 删除 `leptos-tiptap` host 中仅用于切回 `BlockNote` 的 fallback 触发链
- [x]`BlockNote` 从“系统默认可退回编辑器”降为 `recycle` 参考实现
- [x] 活跃设计稿中不再把 `BlockNote` 写成系统 fallback,只允许写成历史对照链
### 4.2 AI provider 直连分支
- [x] 删除 Next `/api/ai-agent/run``provider=codex` 直连分支
- [x] 删除 Next `/api/ai-agent/run``provider=hermes` 直连分支
- [x] 删除 Rust `compat` 中代理到 legacy Next AI route 的优先分支
- [x] 删除 Rust `compat` 中 direct Hermes 分支
- [x] 删除 Rust `compat` 中 document AI orchestrator fallback 分支
- [x] 统一只保留 `mnote-cli` host 作为默认主执行入口
- [x] 次要 provider 请求改为明确失败,不再静默降级
### 4.3 legacy Next compat / alias / debug 壳
- [x] 删除 `/api/mnote-web/stream` 这类 tree stream compat alias
- [x] 删除 `legacy_next_proxy` 默认 fallback
- [x] 删除仅为 legacy Next upstream 保留的 route fallback
- [x] 删除默认可见 debug shell / compat shell 入口
- [x] 仅在明确内部调试需要时,才允许保留隔离后的 debug 文件到 `recycle/`
## 5. 第二波:主链清障后退场
### 5.1 `page aggregate` TS fallback
- [x] 删除 `/api/documents/page` 读链里的 TS builder fallback
- [x] 文档页读取只保留 Rust `/api/page-aggregate/:id` 正式快照
- [x] snapshot 不可用时直接显式失败,不再组装 fallback projection
- [x] 活跃设计稿不再写“Rust-first + TS fallback 混合态”,改成单一路径
### 5.2 页面域本地兼容状态
- [x] 识别 `page aggregate client state` 中仅为旧链兜底存在的字段
- [x] 删除标题 / 页面设置 / 正文之间的兼容性双轨状态
- [x] 删除只服务旧 fallback editor host 的状态同步分支
- [x] 页面域只保留围绕正式 `page.*` command family 的状态回流
### 5.3 tree realtime / sidebar 补偿链
- [x] 删除 preferred snapshot 选择链中只为旧链存在的补偿分支
- [x] 删除 Sidebar / page subtree / filetree 中旧 snapshot 回闪兜底
- [x] `3000` 主壳只保留 `/api/tree/events` snapshot + delta + resync 主链
- [x] 不再为 legacy route 额外维护第二条 live cache 语义
## 6. 第三波:统一归档到 `recycle/`
### 6.1 设计稿与说明
- [x] 将已退场实现对应的设计稿移到 `design/old/``recycle/design/`
- [x] 活跃 `process/` 文档移除对已退场 runtime 的默认依赖描述
- [x] `ARCHITECTURE.md` / `AGENTS.md` 不再把退场对象写成系统组件
### 6.2 参考实现与脚本
- [x] 将退场 runtime 的参考代码移动到 `recycle/` 对应目录
- [x] 将只服务旧链的 smoke / fixture / helper 脚本移到 `recycle/`
- [x] 清除主路径中对这些参考实现的 import、route 注册和 UI 入口
## 7. 执行顺序
- [x] 先完成第一波:砍掉次要入口默认资格
- [x] 再完成第二波:清掉主路径底下的假单一路径
- [x] 最后完成第三波:统一归档文档、脚本和参考代码
## 8. 验收标准
### 8.1 必须成立
- [x] 文档页仍能打开
- [x] Sidebar 仍能使用
- [x] tree realtime 主链仍能工作
- [x] 标题保存、页面设置保存、正文保存仍能工作
- [x] 默认主路径不再出现“切回 legacy / fallback / compat”按钮或自动分支
### 8.2 必须消失
- [x] 默认运行时不再自动触发 `BlockNote` fallback
- [x] 默认 AI 运行时不再直连 `Hermes` / `Codex` / 旧 orchestrator compat
- [x] 默认 gateway 不再把 legacy Next 当作未迁路径的总兜底
- [x] `/api/documents/page` 不再在 runtime 中组装 TS fallback projection
### 8.3 允许接受
- [x] 次要入口直接报错
- [x] 历史 debug 壳直接下线
- [x] 某些只服务旧链的测试暂时删除后再按新主链重建
## 9. 禁止项
- [x] 不以“先保留一下,以后可能有用”为理由继续保活 fallback
- [x] 不把已移入 `recycle/` 的代码继续通过主路径 import 回来
- [x] 不再新增任何新的 compat / fallback / legacy route
- [x] 不通过文档口径美化来掩盖 runtime 仍依赖 fallback 的事实
## 10. 一句话收口
> **这轮不是“继续整理兼容层”,而是“把不再属于系统组件的 fallback 全部赶出主路径,只保留主路径白名单”。**
@@ -231,7 +231,7 @@ Rust Web 负责:
- 首页不能再依赖 3104 实验壳
- `3000` 主入口必须可稳定进入 `/auth` 或文档页
- 实时链路失败时,首屏仍要有稳定 snapshot fallback
- 首屏仍要有稳定 SSR snapshot,但不再通过第二条 runtime projection fallback 偷偷补拉 live 语义
也就是说:
-442
View File
@@ -1,442 +0,0 @@
# 3-4 [process] Rust Web 架构未完成项收口计划与执行清单 v1
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` or `superpowers:executing-plans` when implementing this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking.
**Goal:** 将 3000 Rust Web 从“UI parity 已接近、运行时仍混合兼容层”的状态,收口到以 Rust kernel/projection/command 为主的页面、树、搜索、AI、导图与旧 Next 退役架构。
**Architecture:** Rust kernel / `core-protocol` 持有页面聚合、树命令、搜索投影、导图投影等稳定契约;`bridge-runtime` 暴露 query/command facade`mnote-web` 负责 3000 入口、SSR shell、SSE/live transport 与 island 边界。React/Next 只保留为迁移期 runtime adapter 或 debug 兼容层,不再承载新的对象真相。
**Tech Stack:** Rust workspace (`core-protocol`, `bridge-runtime`, `mnote-web`), Axum, Leptos islands, browser `EventSource`, Playwright/Node smoke scripts, legacy Next compat guard.
---
## 当前架构判断
- [x] 3000 入口已由 Rust Web 承接,文档页 UI 与 Wolai 风格 shell 已有基础形态。
- [x] `/api/tree/events` 已由 Rust Web 提供 SSE transport,并能返回 `text/event-stream`
- [x] `bridge-runtime` 已存在 `page.head.updateTitle``page.layout.updateOptions``page.body.save` 等新命名命令。
- [x] `mnote-web` 已存在本地 `PageAggregate` 类型与 `/api/page-aggregate/{document_id}` 路由。
- [x] Page Aggregate 还未成为 `core-protocol` / kernel 原生 projection 契约。
- [x] 3000 文档保存主链仍有 `documents.save``page.*` 尚未成为唯一默认写面。
- [x] Rust shell 还未消费 `/api/tree/events` 形成 sidebar / page tree / file tree 的 live snapshot + delta + resync 闭环。
- [x] Search 仍是 Rust shell + React island,检索主链还不是 kernel/server-first。
- [x] AI bridge 由 Rust 持有入口,但 AI runtime 与结构化写链仍偏 React island。
- [x] Mindmap 仍是对象 shell / renderer runtime,不是 kernel projection 与 command truth。
- [x] Legacy Next / React compat 默认仍启用,尚未形成退役 gate 与删除清单。
## 不做什么
- [x] 不把新的树排序、页面标题、页面正文、导图结构真相继续写进前端局部 state。
- [x] 不扩大 `documents.*` 为长期命令面,只保留为兼容 alias 与迁移验证入口。
- [x] 不把 `compat route`、fallback proxy、React island 当成新的业务主链。
- [x] 不在 Search、AI、Mindmap 阶段抢先删除现有可用 runtime;每个阶段必须先有 Rust/kernel 主链和 smoke 证明。
- [x] 不移动 `design/*/process``done`,除非真实代码已完成并通过对应验收命令。
## 阶段 APage Aggregate 升级为核心 projection 契约
**目标:** `PageAggregate` 不再只是 `mnote-web` 内部拼装结构,而是跨 `core-protocol``bridge-runtime``mnote-web` 的页面聚合 projection 契约。
**涉及文件:**
- Modify: `rust/crates/core-protocol/src/lib.rs`
- Create or Modify: `rust/crates/core-protocol/src/page_aggregate.rs`
- Modify: `rust/crates/bridge-runtime/src/lib.rs`
- Modify: `rust/crates/mnote-web/src/page_aggregate.rs`
- Modify: `rust/crates/mnote-web/src/page_aggregate/builder.rs`
- Modify: `rust/crates/mnote-web/src/routes/web_shell.rs`
- Test: `rust/crates/core-protocol/src/page_aggregate.rs`
- Test: `rust/crates/bridge-runtime/src/lib.rs`
- Test: `rust/crates/mnote-web/src/page_aggregate/builder.rs`
**Checklist**
- [x]`core-protocol` 新增 `PageAggregateProjection`,字段覆盖页面 id、parent id、title、path、sidebar tree membership、body ref、layout options、updated time、projection version。
- [x]`core-protocol` 新增 `PageAggregateSource` 枚举,明确 `KernelProjection``CompatMetaContentJoin``Fixture` 三类来源,便于迁移期观测。
- [x]`bridge-runtime` 新增 `page.aggregate.get` query facade,输入为 `document_id`,输出为 `PageAggregateProjection`
- [x]`mnote-web/src/page_aggregate.rs` 从本地事实结构改成 core-protocol projection 的 HTTP/SSR adapter。
- [x]`web_shell::page_aggregate` 改为优先调用 `bridge-runtime``page.aggregate.get`,仅在迁移开关允许时走 meta/content join fallback。
- [x]`/api/page-aggregate/{document_id}` 响应头中暴露 projection owner,例如 `x-mnote-page-aggregate-owner: rust-kernel``x-mnote-page-aggregate-owner: compat-join`
- [x] 保留旧 JSON 字段兼容,但新增 typed `projectionVersion``source`,确保前端不需要猜测来源。
- [x] 增加测试:kernel projection 能从 fixture page 生成稳定 `PageAggregateProjection`
- [x] 增加测试:fallback meta/content join 的输出与 core projection 字段名一致。
- [x] 增加测试:`/api/page-aggregate/{document_id}` 在 kernel projection 可用时返回 `source=KernelProjection`
- [x] 文档中记录 Page Aggregate 的单一事实边界,并关联 `design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p core-protocol page_aggregate
cargo test -p bridge-runtime page_aggregate
cargo test -p mnote-web page_aggregate
```
**完成定义:**
- [x] 以上命令退出码均为 0。
- [x] `rg -n "struct PageAggregate" rust/crates` 显示核心 projection 在 `core-protocol``mnote-web` 只做 adapter 或 HTTP contract。
- [x] `curl -I http://127.0.0.1:3000/api/page-aggregate/<document_id>` 能看到 Rust/kernel owner 头;使用真实 id 验证。
## 阶段 B:`page.*` 成为页面默认写命令族
**目标:** 页面标题、页面设置、正文保存默认通过 `page.*` 命令进入 Rust kernel/bridge`documents.*` 只作为兼容 alias 继续被测试覆盖。
**涉及文件:**
- Modify: `rust/crates/mnote-web/src/routes/documents.rs`
- Modify: `rust/crates/mnote-web/src/routes/tree.rs`
- Modify: `rust/crates/bridge-runtime/src/lib.rs`
- Modify: `rust/crates/mnote-web/src/routes/web_shell.rs`
- Modify: `wolai-frontend/src/components/editor/DocumentEditorIsland.runtime.tsx`
- Modify: `wolai-frontend/src/components/editor/DocumentTitle*.tsx`
- Test: `rust/crates/bridge-runtime/src/lib.rs`
- Test: `rust/crates/mnote-web/src/routes/documents.rs`
- Test: `scripts/task121-rust-web-editor-island-hydration-smoke.js`
- Test: `scripts/task122-rust-web-create-page-ui-smoke.js`
**Checklist**
- [x]`rust/crates/mnote-web/src/routes/documents.rs` 的正文保存默认命令从 `documents.save` 改为 `page.body.save`
- [x] 保留 `/api/documents/save` HTTP route 名称作为迁移期兼容入口,但响应里标注 executed command 为 `page.body.save`
- [x] 为标题保存写面确认或新增 Rust Web route,内部命令统一使用 `page.head.updateTitle`
- [x] 为页面布局/设置写面确认或新增 Rust Web route,内部命令统一使用 `page.layout.updateOptions`
- [x]`bridge-runtime` tests 中保留 `documents.save``documents.title.update``documents.options.update` alias 映射测试,证明旧命名不会静默断链。
- [x] 在 3000 文档页 island 保存路径中加入 command family observability,页面保存后可从响应或调试日志确认 `page.*`
- [x] 新增 smoke:创建页面、改标题、输入正文、刷新页面后标题和正文仍一致。
- [x] 新增 smoke:旧 compat alias 请求仍返回兼容成功,但响应里声明 canonical command 为 `page.*`
- [x] 将设计文档中仍要求 `documents.*` 作为主链的段落移动到对应 `old/process`,并标记为 `[recycle]`
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p bridge-runtime page_body_save
cargo test -p bridge-runtime page_head_update_title
cargo test -p bridge-runtime page_layout_update_options
cargo test -p mnote-web documents_save
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task121-rust-web-editor-island-hydration-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task122-rust-web-create-page-ui-smoke.js
```
**完成定义:**
- [x] 新页面创建、标题保存、正文保存、刷新恢复均走 3000。
- [x] `rg -n "documents\.save|documents\.title\.update|documents\.options\.update" rust/crates/mnote-web/src` 只剩兼容入口、alias 测试或明确迁移注释。
- [x] `bridge-runtime``documents.*` 的支持被标记为 compat alias,不再被主链调用。
## 阶段 C3000 Rust shell 消费 tree realtime event stream
**目标:** 3000 页面树/文件树不只依赖 SSR snapshot 与交互后重读,而是通过 `/api/tree/events` 建立 live snapshot + delta + resync cache。
**涉及文件:**
- Modify: `rust/crates/mnote-web/src/routes/sse.rs`
- Modify: `rust/crates/mnote-web/src/routes/web_shell.rs`
- Modify: `rust/crates/mnote-web/src/routes/tree.rs`
- Create or Modify: `rust/crates/mnote-web/assets/tree-live-controller.js`
- Modify: `rust/crates/mnote-web/src/assets.rs`
- Test: `rust/crates/mnote-web/src/routes/sse.rs`
- Test: `scripts/task120-rust-web-tree-integration-smoke.js`
- Create: `scripts/task123-rust-web-tree-live-stream-consumer-smoke.js`
**Checklist**
- [x] 为 Rust shell 输出添加 tree live bootstrap contractworkspace id、root ids、initial revision、SSE endpoint、resync endpoint。
- [x] 编写浏览器端 `tree-live-controller.js`,职责仅包括连接 `EventSource`、解析 snapshot/delta/resync、派发 DOM 自定义事件。
- [x] 将页面树和文件树 DOM 标记为同一 tree projection 的两个 view,而不是两套独立对象源。
- [x] 实现 `tree:snapshot` 事件处理:首包对齐 SSR snapshot revision,不一致时触发 resync。
- [x] 实现 `tree:delta` 事件处理:create/rename/move/archive/purge 更新当前 DOM view,不整页 reload。
- [x] 实现断线重连:`EventSource.onerror` 后记录状态并使用浏览器原生重连;连续失败后调用 resync endpoint。
- [x]`/api/tree/events` 中补齐 event id / revision 字段,便于客户端判断是否漏包。
- [x] 新增 smoke:打开 3000,断言 network 中存在 `/api/tree/events` EventSource 请求。
- [x] 新增 smoke:通过 Rust Web tree command 创建页面后,当前页面树无需刷新即可出现节点。
- [x] 新增 smoke:通过 Rust Web tree command 重命名页面后,当前页面树和文件树同时更新。
- [x] 新增 smoke:模拟 SSE 断开后,客户端能恢复到最新 revision。
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p mnote-web tree_events
cargo test -p mnote-web tree_command
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task120-rust-web-tree-integration-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js
```
**完成定义:**
- [x] 3000 首屏源码或 hydrated DOM 中可定位 tree live bootstrap contract。
- [x] Playwright network 记录包含 `/api/tree/events`,响应类型为 `eventsource``text/event-stream`
- [x] 创建、重命名、移动、归档页面后,页面树和文件树都能在不刷新的情况下更新。
## 阶段 DSearch 收口为 server-first / kernel-aware 检索主链
**目标:** `/search` 不再只是 React search palette 宿主;Rust/kernel 持有搜索输入、结果 projection、权限过滤和初始 SSR 结果。
**涉及文件:**
- Modify: `rust/crates/core-protocol/src/lib.rs`
- Create or Modify: `rust/crates/core-protocol/src/search.rs`
- Modify: `rust/crates/bridge-runtime/src/lib.rs`
- Modify: `rust/crates/mnote-web/src/routes/search.rs`
- Modify: `wolai-frontend/src/components/search/*`
- Test: `rust/crates/core-protocol/src/search.rs`
- Test: `rust/crates/bridge-runtime/src/lib.rs`
- Test: `rust/crates/mnote-web/src/routes/search.rs`
- Create: `scripts/task125-rust-web-search-server-first-smoke.js`
**Checklist**
- [x]`core-protocol` 定义 `SearchQuery``SearchResultProjection``SearchScope``SearchHighlight`
- [x]`bridge-runtime` 新增 `search.documents.query` query facade,返回排序稳定的 `SearchResultProjection` 列表。
- [x] `/api/search/documents` 改为调用 `bridge-runtime` query facade,不直接拼 legacy search wrapper。
- [x] `/search` SSR shell 根据 URL query 渲染首批结果,空 query 渲染最近访问或 pinned scope。
- [x] React search palette 降级为 keyboard / focus / incremental interaction island,结果数据来自 Rust search endpoint。
- [x] 搜索结果 contract 中加入 `projectionOwner: "rust-kernel"``projectionOwner: "compat-index"`,便于迁移观测。
- [x] 增加测试:同一 query 在 fixture 数据下返回稳定顺序。
- [x] 增加测试:权限或 workspace scope 不匹配的页面不会出现在结果里。
- [x] 增加 smoke:访问 `/search?q=<keyword>` 时首屏 HTML 已包含匹配结果。
- [x] 增加 smoke:键盘打开搜索、输入关键字、选择结果后跳转到 3000 文档页。
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p core-protocol search
cargo test -p bridge-runtime search_documents_query
cargo test -p mnote-web search
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task125-rust-web-search-server-first-smoke.js
```
**完成定义:**
- [x] `curl http://127.0.0.1:3000/search?q=<keyword>` 的 HTML 中包含 server-rendered result list。
- [x] `rust/crates/mnote-web/src/routes/search.rs` 的 contract 不再声明主 runtime 为 `react_search_palette`
- [x] React 搜索组件只负责交互增强,不拥有检索真相或排序真相。
## 阶段 EAI bridge 与结构化写链收口
**目标:** Hermes/Rust bridge 成为 AI 会话、工具调用、事件流与结构化写入的主链;React AI panel 仅作为交互壳。
**涉及文件:**
- Modify: `rust/crates/core-protocol/src/lib.rs`
- Create or Modify: `rust/crates/core-protocol/src/ai.rs`
- Modify: `rust/crates/bridge-runtime/src/lib.rs`
- Modify: `rust/crates/mnote-web/src/routes/hermes.rs`
- Modify: `wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx`
- Test: `rust/crates/core-protocol/src/ai.rs`
- Test: `rust/crates/bridge-runtime/src/lib.rs`
- Test: `rust/crates/mnote-web/src/routes/hermes.rs`
- Create: `scripts/task126-rust-web-ai-bridge-structured-write-smoke.js`
**Checklist**
- [x]`core-protocol` 定义 AI session、AI tool call、AI event、structured write result 的协议类型。
- [x]`bridge-runtime` 新增 AI tool facade,允许 AI 写入 `summary node``ai_note node``reference edge`
- [x] `/api/hermes/bridge` 返回 Rust-owned session id 与 event stream endpoint,不再把 runtimeRole 标为 `react_interaction_island` 主链。
- [x] `/api/ai-agent/run` 保留为 legacy compat endpoint,并在响应中指向 `/api/hermes/bridge` canonical route。
- [x] React AI panel 改为只发送用户意图、展示事件流和确认结构化写入结果。
- [x] AI 写入页面正文时必须通过 `page.body.save` 或更细粒度 page body command,不直接写前端 editor state。
- [x] AI 创建 summary/ai_note/reference 时必须通过 tree/page/edge command,不直接拼 JSON blob。
- [x] 增加测试:Hermes bridge 可以产生 session、tool call event、structured write result。
- [x] 增加测试:legacy `/api/ai-agent/run` 返回兼容结果,并标明 canonical route。
- [x] 增加 smoke:在 3000 文档页触发 AI 生成摘要,刷新后 summary node 仍存在于 tree/page projection。
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p core-protocol ai
cargo test -p bridge-runtime ai_tool
cargo test -p mnote-web hermes
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task126-rust-web-ai-bridge-structured-write-smoke.js
```
**完成定义:**
- [x] `DocumentAiAgentPanel.runtime.tsx` 不再声明 AI 主链为 React runtime owner。
- [x] AI 写入结果能从 Page Aggregate 或 tree projection 读回。
- [x] legacy AI endpoint 不再被 3000 默认 UI 主动调用。
## 阶段 FMindmap 成为 kernel projection / command truth
**目标:** Mindmap 从对象 shell 与 React renderer runtime,收口为 kernel projection + command facade`simple-mind-map` 只保留为 renderer adapter。
**涉及文件:**
- Modify: `rust/crates/core-protocol/src/mindmap.rs`
- Modify: `rust/crates/bridge-runtime/src/lib.rs`
- Modify: `rust/crates/mnote-web/src/routes/mindmap_shell.rs`
- Modify: `wolai-frontend/src/components/mindmap/*`
- Test: `rust/crates/core-protocol/src/mindmap.rs`
- Test: `rust/crates/bridge-runtime/src/lib.rs`
- Test: `rust/crates/mnote-web/src/routes/mindmap_shell.rs`
- Create: `scripts/task127-rust-web-mindmap-kernel-projection-smoke.js`
**Checklist**
- [x]`core-protocol` 明确 `MindmapProjection`,字段包括 map id、root node、node list、edge list、layout hints、revision、owner。
- [x]`core-protocol` 明确 `MindmapCommand`,覆盖 create node、rename node、move node、delete node、set layout、attach page ref。
- [x]`bridge-runtime` 新增 `mindmap.projection.get` query facade。
- [x]`bridge-runtime` 新增 `mindmap.command.apply` command facade。
- [x]`mindmap_apply_ops` 从 compat blob mutation 改为调用 kernel command facade。
- [x] `/mindmap/{doc_id}/{mindmap_id}` SSR contract 不再标记 `legacyCompat: next-app-router` 为主链。
- [x] React mindmap runtime 只接收 `MindmapProjection` 并发出 `MindmapCommand`,不持久化对象真相。
- [x] AI/CLI 写导图时使用同一 `mindmap.command.apply`,不绕开 kernel。
- [x] 增加测试:create/rename/move/delete command 后 projection revision 单调递增。
- [x] 增加 smoke:在 3000 导图页新增节点、刷新、节点仍存在且 owner 为 Rust/kernel。
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p core-protocol mindmap
cargo test -p bridge-runtime mindmap
cargo test -p mnote-web mindmap
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task127-rust-web-mindmap-kernel-projection-smoke.js
```
**完成定义:**
- [x] `rust/crates/mnote-web/src/routes/mindmap_shell.rs` 的 contract 显示 Rust/kernel projection owner。
- [x] `simple-mind-map` adapter 不再直接决定持久化格式。
- [x] Mindmap 与 page/tree/edge 的关系能通过 kernel query 读回。
## 阶段 GLegacy Next / React 兼容层退役 gate
**目标:** 旧 Next/React 兼容层从默认可用主链,降级为显式 debug/internal fallback,并具备逐项删除清单。
**涉及文件:**
- Modify: `rust/crates/mnote-web/src/app.rs`
- Modify: `rust/crates/mnote-web/src/routes/mod.rs`
- Modify: `rust/crates/mnote-web/src/routes/gateway.rs`
- Modify: `rust/crates/mnote-web/src/config.rs`
- Modify: `scripts/task117-next-retirement-guard.js`
- Create or Modify: `design/03-rust-web/done/3-11-rust-web-legacy-next-retirement-gates-v1.md`
**Checklist**
- [x] 盘点 `routes/mod.rs` 中所有 `/api/compat/next`、fallback proxy、legacy debug route 的入口和调用方。
- [x]`enable_legacy_next_compat` 默认值从“迁移期默认开启”推进到“仅显式环境变量开启”,并保留清晰错误页。
- [x] 为 3000 主入口增加 guard:默认首页、文档页、搜索页、导图页不得落到 Next proxy。
- [x] `task117-next-retirement-guard.js` 增加断言:未设置 debug/env 时访问主路径不出现 Next fallback header。
- [x] 为确需保留的 Next route 标注用途:debug、fixture、runtime 对照或临时迁移。
- [x] 为每个保留 route 写删除条件:替代 Rust route、对应 smoke、对应 owner。
- [x] 文档整理:已被当前实现覆盖的旧计划移动到 `design/old/process` 或对应 `done`,标题标记 `[recycle]``[done]`
- [x] 删除前最后一轮检查:`rg -n "legacy_next|compat/next|next-app-router|fallback proxy" rust/crates/mnote-web wolai-frontend design` 输出必须逐项有 owner。
**验收命令:**
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p mnote-web gateway
cargo test -p mnote-web legacy_next
cd /mnt/Data1T/mnote
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task117-next-retirement-guard.js
```
**完成定义:**
- [x] 3000 主路径在默认配置下不依赖 Next proxy。
- [x] legacy compat 只能由明确 debug/internal 配置启用。
- [x] 设计目录中旧 Next 主链文档不再占用活跃 `process`
## 阶段 H:设计文档状态治理与执行节奏
**目标:** 每个阶段实现后,设计目录真实反映当前代码状态,避免已完成、已覆盖、未完成计划混在 `process` 中。
**涉及文件:**
- Modify: `design/03-rust-web/process/*.md`
- Modify: `design/03-rust-web/done/*.md`
- Modify: `design/old/process/*.md`
- Modify: `design/old/done/*.md`
- Modify: `harness-tasks.json`
**Checklist**
- [x] 每完成一个阶段,在本文件对应阶段勾选完成项,并写入验收命令的实际结果摘要。
- [x] 若某份 `design/03-rust-web/process/*.md` 已由真实代码完成,将其移动到 `design/03-rust-web/done/` 并在标题标注 `[done]`
- [x] 若某份活跃设计稿已被后续计划覆盖但代码未完成,将其移动到 `design/old/process/` 并在标题标注 `[recycle]`
- [x] 若某份旧稿已完成但属于历史路径,将其移动到 `design/old/done/` 并在标题标注 `[recycle][done]`
- [x] 更新 `harness-tasks.json`,让阶段 A-G 具备可恢复任务 id、依赖关系、验收命令和当前状态。
- [x] 每次实现阶段结束前运行 `git diff --check`,避免文档空白错误与编码问题。
- [x] 每次实现阶段结束前运行 `git status --short --untracked-files=all`,确认只包含本阶段预期文件。
**验收命令:**
```bash
cd /mnt/Data1T/mnote
rg -n "\[ \]" design/03-rust-web/process/3-4-undo.md
rg -n "\[done\]|\[recycle\]" design/03-rust-web design/old
git diff --check
git status --short --untracked-files=all
```
**完成定义:**
- [x] 本文件每个阶段的 checkbox 状态与代码状态一致。
- [x] `design/03-rust-web/process/` 只保留仍需执行的活跃计划。
- [x] `harness-tasks.json` 能表达阶段依赖:A -> B/C -> D/E/F -> G -> H。
## 推荐执行顺序
- [x] 先执行阶段 APage Aggregate 协议上移,避免页面壳继续拼第二份页面真相。
- [x] 再执行阶段 B`page.*` 写命令切主链,确保编辑器保存、标题、设置都落到同一命令族。
- [x] 再执行阶段 Ctree realtime 消费闭环,解决页面树/文件树 runtime 不一致问题。
- [x] 然后并行准备阶段 D、E、F,但实施时分别通过独立 smoke 验收,避免 Search/AI/Mindmap 互相牵连。
- [x] 最后执行阶段 G、H:legacy gate 与设计文档状态治理必须以真实功能验收为前提。
## 全局验收矩阵
| 能力 | 关键证明 | 命令 |
| --- | --- | --- |
| Page Aggregate | core-protocol 持有 projection3000 API 暴露 owner | `cargo test -p core-protocol page_aggregate && cargo test -p mnote-web page_aggregate` |
| 页面写命令 | 3000 保存主链使用 `page.*``documents.*` 仅 compat | `cargo test -p bridge-runtime page_body_save && node scripts/task122-rust-web-create-page-ui-smoke.js` |
| Tree realtime | 3000 建立 EventSource,并能 delta 更新页面树/文件树 | `cargo test -p mnote-web tree_events && node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js` |
| Search | `/search?q=` 首屏返回 server-rendered results | `cargo test -p mnote-web search && node scripts/task125-rust-web-search-server-first-smoke.js` |
| AI | AI 写入通过 Rust bridge 与 page/tree/edge command 读回 | `cargo test -p mnote-web hermes && node scripts/task126-rust-web-ai-bridge-structured-write-smoke.js` |
| Mindmap | 导图 projection/command 由 kernel 持有 | `cargo test -p bridge-runtime mindmap && node scripts/task127-rust-web-mindmap-kernel-projection-smoke.js` |
| Legacy retirement | 默认 3000 主路径不走 Next proxy | `cargo test -p mnote-web gateway && node scripts/task117-next-retirement-guard.js` |
## 提交建议
- [x] 阶段 A 提交:`feat: promote page aggregate projection contract`
- [x] 阶段 B 提交:`feat: route page writes through page commands`
- [x] 阶段 C 提交:`feat: consume tree realtime stream in rust shell`
- [x] 阶段 D 提交:`feat: make search server-first in rust web`
- [x] 阶段 E 提交:`feat: route ai structured writes through rust bridge`
- [x] 阶段 F 提交:`feat: promote mindmap kernel projection commands`
- [x] 阶段 G 提交:`refactor: gate legacy next compat behind explicit debug`
- [x] 阶段 H 提交:`docs: reconcile rust web design status`
## 当前文件状态
- [x] 本计划文件被 `.gitignore``design` 规则忽略;如需纳入提交,使用 `git add -f design/03-rust-web/process/3-4-undo.md`
- [x] 本计划只是执行清单,不代表阶段 A-G 已完成;只有真实代码改动与验收命令通过后才能勾选对应完成项。
## 2026-04-29 执行结果摘要
- [x] 阶段 A`core-protocol` 已新增 Page Aggregate projection/source 契约;`bridge-runtime` 已新增 `page.aggregate.get` facade`mnote-web` `/api/page-aggregate/{document_id}` 返回 `source=KernelProjection` 并暴露 `x-mnote-page-aggregate-owner: rust-kernel`
- [x] 阶段 B`/api/documents/save` 兼容 HTTP route 内部默认执行 `page.body.save`;新增 `/api/documents/title``/api/documents/options`,分别执行 `page.head.updateTitle``page.layout.updateOptions`
- [x] 阶段 CRust shell 输出 `mnote.tree_live_bootstrap.v1`,内联 tree live controller 建立 `/api/tree/events` EventSource,并派发 `tree:snapshot``tree:delta``tree:resync`SSE 事件补齐 `id``revision`
- [x] 阶段 D:新增 `core-protocol/src/search.rs``bridge-runtime` 支持 canonical `search.documents.query``/search?q=` SSR 首屏渲染结果列表并标注 `projectionOwner=rust-kernel`
- [x] 阶段 E:新增 `core-protocol/src/ai.rs`Hermes bridge 返回 Rust-owned session、event stream endpoint、structured write owner`DocumentAiAgentPanel.runtime.tsx` 默认请求 `/api/hermes/bridge`
- [x] 阶段 F`core-protocol` 已定义 `MindmapProjection` / `MindmapCommand``bridge-runtime` 已支持 `mindmap.projection.get` / `mindmap.command.apply`;导图 shell 不再声明 `next-app-router` 主链。
- [x] 阶段 G`MNOTE_WEB_ENABLE_LEGACY_NEXT_COMPAT` 默认关闭;task117 覆盖首页、文档页、搜索页、导图页与 tree SSE 均不出现 Next fallback header。
- [x] 阶段 H:新增 `3-11-rust-web-legacy-next-retirement-gates-v1.md`,并在 `harness-tasks.json` 记录 A-G/H 的可恢复阶段链与验收命令。
实际已运行验收:
```bash
cd /mnt/Data1T/mnote/rust
cargo test -p core-protocol page_aggregate
cargo test -p core-protocol search
cargo test -p core-protocol ai
cargo test -p core-protocol mindmap
cargo test -p bridge-runtime page_aggregate
cargo test -p bridge-runtime search_documents_query
cargo test -p bridge-runtime mindmap
cargo test -p bridge-runtime page_body_save
cargo test -p bridge-runtime page_head_update_title
cargo test -p bridge-runtime page_layout_update_options
cargo test -p mnote-web page_aggregate
cargo test -p mnote-web documents_save
cargo test -p mnote-web tree_events
cargo test -p mnote-web tree_command
cargo test -p mnote-web search
cargo test -p mnote-web hermes
cargo test -p mnote-web mindmap
cargo test -p mnote-web gateway
cargo test -p mnote-web legacy_next
cd /mnt/Data1T/mnote
node scripts/task117-next-retirement-guard.js
MNOTE_UI_BASE_URL=http://127.0.0.1:<temp-port> node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:<temp-port> node scripts/task125-rust-web-search-server-first-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:<temp-port> node scripts/task126-rust-web-ai-bridge-structured-write-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:<temp-port> node scripts/task127-rust-web-mindmap-kernel-projection-smoke.js
```
@@ -58,7 +58,7 @@
- **Web 承载层:`axum`**
- **页面渲染模型:`Leptos Islands`**
- **AI 执行面:`mnote-cli`**
- **最后保留的重编辑兼容孤岛:少量编辑器 runtime(当前默认主编辑器已是页面内 `leptos-tiptap` island`BlockNote` 仅保留为 fallback / 对照链**
- **最后保留的重编辑兼容孤岛:少量编辑器 runtime(当前默认主编辑器已是页面内 `leptos-tiptap` island`BlockNote` 仅保留为 `recycle/` 历史参考副本**
一句话概括:
@@ -68,7 +68,7 @@
当前真正难替代的主要是:
-`BlockNote` fallback、转换链和剩余兼容保存链为代表的重编辑 runtime
- `BlockNote` 编辑器副本、转换链和剩余兼容保存链为代表的重编辑 runtime
而下面这些能力,从长期看都可以先退出当前大前端壳:
@@ -359,8 +359,8 @@ Leptos Islands 很适合承接下面这类长期目标:
- `mnote-web` 已经不是只停留在 crate 骨架;`3000` 公开入口已由 Rust Web 主壳承接,`3104` 已退到仅显式 debug / internal 边界。
- Rust Web 主壳已经接入 `/api/tree/events` snapshot / delta / resync consumer,双 pane 也已复用同一条 tree realtime 主链,而不是每个页面壳各自维护第二条流。
- 文档页读取已经进入 Rust-first `page aggregate` 过渡态:`/api/documents/page` 优先消费 Rust `/api/page-aggregate/:id``mnote.page_aggregate.v1` snapshot,失败时才回退 TS builder
- 默认主编辑区已经切到页面内 `leptos-tiptap` island;阅读态、页头、页面设置和页面内 AI 面板都在 `3000` 主壳上继续收口,`BlockNote` 只保留为 fallback / 对照
- 文档页读取已收口到 Rust `/api/page-aggregate/:id``mnote.page_aggregate.v1` snapshot`/api/documents/page` 已降级为显式退场的 compat 边界,不再参与运行时主路径
- 默认主编辑区已经切到页面内 `leptos-tiptap` island;阅读态、页头、页面设置和页面内 AI 面板都在 `3000` 主壳上继续收口,`BlockNote` 只保留为 `recycle/` 历史参考 / 对照材料
- Sidebar 已形成“服务端首包 + 客户端局部 island”的最小边界,导航数据聚合契约不再散落在布局层。
- SearchPalette 与页面级 AI 面板都已经收成轻 host + 按需 runtime island,重量运行态不再默认跟随主布局常驻。
- Global AI 继续保留为实验入口,但不再回到 app layout 主链,避免长期路线再次滑回“全局大面板常驻”模式。