# 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`,除非真实代码已完成并通过对应验收命令。 ## 阶段 A:Page 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/` 能看到 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,不再被主链调用。 ## 阶段 C:3000 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 contract:workspace 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] 创建、重命名、移动、归档页面后,页面树和文件树都能在不刷新的情况下更新。 ## 阶段 D:Search 收口为 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=` 时首屏 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=` 的 HTML 中包含 server-rendered result list。 - [x] `rust/crates/mnote-web/src/routes/search.rs` 的 contract 不再声明主 runtime 为 `react_search_palette`。 - [x] React 搜索组件只负责交互增强,不拥有检索真相或排序真相。 ## 阶段 E:AI 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 主动调用。 ## 阶段 F:Mindmap 成为 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 读回。 ## 阶段 G:Legacy 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/process/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] 先执行阶段 A:Page Aggregate 协议上移,避免页面壳继续拼第二份页面真相。 - [x] 再执行阶段 B:`page.*` 写命令切主链,确保编辑器保存、标题、设置都落到同一命令族。 - [x] 再执行阶段 C:tree realtime 消费闭环,解决页面树/文件树 runtime 不一致问题。 - [x] 然后并行准备阶段 D、E、F,但实施时分别通过独立 smoke 验收,避免 Search/AI/Mindmap 互相牵连。 - [x] 最后执行阶段 G、H:legacy gate 与设计文档状态治理必须以真实功能验收为前提。 ## 全局验收矩阵 | 能力 | 关键证明 | 命令 | | --- | --- | --- | | Page Aggregate | core-protocol 持有 projection,3000 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] 阶段 C:Rust 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: node scripts/task123-rust-web-tree-live-stream-consumer-smoke.js MNOTE_UI_BASE_URL=http://127.0.0.1: node scripts/task125-rust-web-search-server-first-smoke.js MNOTE_UI_BASE_URL=http://127.0.0.1: node scripts/task126-rust-web-ai-bridge-structured-write-smoke.js MNOTE_UI_BASE_URL=http://127.0.0.1: node scripts/task127-rust-web-mindmap-kernel-projection-smoke.js ```