# 7-4 [done] 页面 AI Hermes 面板顺序执行 checklist v1

> 更新时间：2026-05-14
>
> 当前状态：`DONE`。A-M 的实现、旧链退场、持久化审计和正式 `3000` 全矩阵已完成；N 文档治理已把活跃设计口径统一为 Hermes 页面内客户端 + mnote Hermes skill/plugin。本文已从 `process/` 迁入 `done/`；后续页面 AI 体验与设置面收口由 `design/07-ai/process/7-7-page-ai-mini-hermes-control-surface-v1.md` 继续承接。
>
> 上位依据：
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-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/done/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-10-wolai-page-settings-and-ai-surface-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-11-wolai-page-settings-and-ai-surface-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-2-phase7-structured-artifact-write-chain-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`
>
> 目标：
> - 把页面 AI 从旧 `/api/ai-agent/run` / `mnote-cli host` / sidecar 路径迁到 Hermes 页面内客户端。
> - Hermes 持有 AI session/message/tool event/usage/model 真相。
> - mnote 只通过 Hermes skill/plugin 暴露页面、树、artifact、edge 等业务工具。
> - Leptos 负责页面内 Hermes 面板体验，不负责 AI 编排或聊天真相存储。

---

## 0. 使用方式

每次只领取一个 task，按顺序执行。除非前一 task 的验收标准全部满足，否则不要进入下一 task。

勾选规则：

- [x] 已有代码、文档和可复跑验证证据。
- [ ] 还没有完整证据，或只有局部实现。
- [ ] `PARTIAL` 项不能当作完成项；必须继续拆到对应未勾选子项。

状态标记：

- `TODO`：未开始
- `RED`：已补失败测试或失败 smoke
- `GREEN`：当前 task 本地通过
- `BLOCKED`：依赖外部 Hermes、auth、模型网关或数据权限，无法在本轮闭环
- `DONE`：代码、测试、文档证据都已回填

执行硬规则：

- [x] 不新增 Web 私有 AI tool registry。
- [x] 不把 Hermes 聊天消息复制进 mnote page aggregate / Convex 页面数据。
- [x] 不让 Hermes plugin 直接写 Convex，写入必须回到 Rust runtime / kernel。
- [x] 不把 `mnote-cli` 写回页面 AI 唯一长期执行面；它最多是 plugin 内部 adapter 或调试入口。
- [x] 不在页面 AI 抽屉里复刻 Hermes 管理台；只实现页面内 chat/session/run/tool event 子集。
- [x] 不在同一阶段同时迁移所有工具；先读、再写正文、再 artifact、再树与 edge。

当前进度快照：

| Task | 状态 | 已有证据 | 剩余门槛 |
| --- | --- | --- | --- |
| A | [x] GREEN | `scripts/task-hermes-page-ai-baseline-smoke.js`、`bugs/07-ai/done/7-1-page-ai-provider-hermes-old-run-502-v1.md` | 无 |
| B | [x] GREEN | `design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md` | 无 |
| C | [x] GREEN | `rust/crates/mnote-web/src/routes/hermes_client.rs`、`cargo test -p mnote-web hermes_` | 无 |
| D | [x] GREEN | `design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md` | 无 |
| E | [x] GREEN | `rust/crates/mnote-web/src/routes/hermes_tools.rs`、`rust/crates/mnote-web/src/hermes_tools/*`、`task-hermes-page-ai-tool-smoke.js` | 后续可扩 manifest 全量 schema，不阻塞第一版只读工具 |
| F | [x] GREEN | `rust/crates/mnote-web/src/ssr/pages/layout.rs`、`task-hermes-page-ai-smoke.js` | 无 |
| G | [x] GREEN | 真实 Hermes upstream run 已触发 `mnote_page_get` / `mnote.page.get`；Hermes session export 与刷新恢复已验证 | 无 |
| H | [x] GREEN | `mnote.page.save` route、dryRun、未认证拒绝、workspace ACL 失败、同 key replay、主编辑区立即回显与刷新后持久化 smoke 已有 | 无 |
| I | [x] GREEN | `mnote.page.update_title`、`mnote.page.update_options` route 与 smoke 已有；标题 dryRun / idempotency、wired-only warning、页头 / breadcrumb / sidebar / 刷新后一致性已验证 | 无 |
| J | [x] GREEN | `mnote.artifact.create_summary`、`mnote.artifact.create_ai_note` route 与 smoke 已有；summary 重试、ai_note 独立创建、真实 kernel/projection edge 查询、`AI Artifacts` projection-only 验收和页面 AI Hermes intent 快捷入口已通过 | 无 |
| K | [x] GREEN | 新页面 AI 主链已不请求 `/api/ai-agent/run`；旧 endpoint 统一返回 `410 legacy_ai_agent_run_retired`；旧 smoke 默认退役；legacy 调用方已清点并归类 | 无 |
| L | [x] GREEN | tool 响应已有基础 audit 字段；`routes/hermes_tools.rs` 已记录 started/completed/failed 结构化日志；写工具 `audit.commandId` 已指向 Rust command id；审计已追加 JSONL 持久化并支持 `persistedOnly=true` 反查 | 无 |
| M | [x] GREEN | 正式 `http://127.0.0.1:3000` 已复跑 8 个 E2E smoke：session/run、tool、writeback、title/options、artifact、retirement、mobile、audit | 无 |
| N | [x] GREEN | 7-3/7-4/7-5/7-6 已写入主线口径；`1-1`、`3-1`、`5-6`、`5-9`、`10-review` 已统一旧 AI 口径为历史/兼容/已覆盖 | 后续若移动本文件到 `done/`，需同步更新引用 |

---

## 1. Hermes Web UI 参考索引

需要参考 `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18` 时，只参考下表列出的文件。参考目标是理解 Hermes 的 session / run / stream / tool event / usage / model 语义，不照搬 Vue、Naive UI、整站导航或后台管理页面。

执行时按 task 精确打开文件，不要整目录通读。需要进一步定位时，优先按下表的“搜索点”打开，不要从整站 UI 或无关管理页开始看：

| 参考主题 | 文件 | 搜索点 / 具体位置 | 在 mnote 中用于什么 |
| --- | --- | --- | --- |
| 浏览器发起 run 与事件分发 | `packages/client/src/api/hermes/chat.ts` | `StartRunRequest`、`RunEvent`、`registerSessionHandlers`、`connectChatRun`、`startRunViaSocket` | 对齐 mnote Leptos 面板发起 run、订阅 `message.delta` / `tool.started` / `tool.completed` / `run.completed` 的事件语义 |
| session 刷新恢复 | `packages/client/src/api/hermes/chat.ts`、`packages/client/src/stores/hermes/chat.ts` | `resumeSession`、`switchSession`、`refreshActiveSession`、`mapHermesMessages` | 对齐页面刷新后从 Hermes session detail / resume 恢复消息，而不是从 mnote 本地 state 恢复聊天真相 |
| tool message 前端归并 | `packages/client/src/stores/hermes/chat.ts` | `Message.role = 'tool'`、`toolCallId`、`toolArgs`、`toolResult`、`case 'tool.started'`、`case 'tool.completed'` | 对齐 mnote 面板如何把 tool started / completed 合并成可读消息项 |
| tool message 展示 | `packages/client/src/components/hermes/chat/MessageItem.vue` | `message.role === 'tool'`、`formatToolPayload`、`toolExpanded`、`tool-preview`、`tool-details` | 对齐 tool 结果默认折叠、摘要展示、详细 JSON 展开的交互边界 |
| 页面面板分层 | `packages/client/src/components/hermes/chat/ChatPanel.vue` | `showSessions`、`activeSessionTitle`、`handleNewChat`、`MessageList`、`ChatInput`、`SessionListItem` | 只参考 session list / message list / input 的分层，不复制 Vue / Naive UI / Hermes 全屏布局 |
| 后端 run 与 resume 房间 | `packages/server/src/services/hermes/chat-run-socket.ts` | `ChatRunSocket`、`onConnection`、`resumeSession`、`handleRun`、`emit`、`markCompleted` | 对齐 upstream run 生命周期、刷新恢复、房间广播与终止态，不在 mnote 里重建 Hermes 编排器 |
| OpenAI Responses tool event 映射 | `packages/server/src/services/hermes/chat-run-socket.ts` | `applyResponseStreamEvent`、`response.output_item.done`、`function_call`、`function_call_output`、`tool.started`、`tool.completed`、`flushResponseRunToDb` | 对齐真实 Hermes upstream run 如何产生 tool event，并把 tool call / tool result 写回 Hermes session 存储 |
| Hermes session 存储真相 | `packages/server/src/db/hermes/session-store.ts` | `HermesSessionRow`、`HermesMessageRow`、`createSession`、`getSessionDetail`、`addMessage`、`updateSessionStats` | 明确 session/message/tool call 真相在 Hermes，不在 mnote page aggregate / Convex 页面数据 |
| session HTTP detail | `packages/client/src/api/hermes/sessions.ts`、`packages/server/src/routes/hermes/sessions.ts` | `fetchSessions`、`fetchSession`、`HermesMessage`、`/api/hermes/sessions/:id` | 对齐 session list/detail 的字段名，用于 mnote proxy 返回兼容形状 |
| plugin/skill 清单发现 | `packages/server/src/services/hermes/plugins.ts` | `PYTHON_BRIDGE`、`PluginManager`、`user_dir = get_hermes_home() / "plugins"`、`manifest_list`、`providesTools`、`listHermesPlugins` | 对齐 Hermes Web UI 如何发现 user/project plugin 和 `provides_tools`；mnote 的真正工具必须进入 Hermes plugin/tool registry，不能只停在 mnote-web 私有 route |
| plugin/skill API 外观 | `packages/client/src/api/hermes/plugins.ts`、`packages/client/src/api/hermes/skills.ts`、`packages/server/src/routes/hermes/plugins.ts`、`packages/server/src/routes/hermes/skills.ts` | `list` / `get` / `enable` / `disable` 类 route 与响应字段 | 只用于清单和状态展示口径；页面 AI 第一版不复刻 Hermes plugin 管理台 |

可快速 grep：

```bash
cd /mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18
rg -n "StartRunRequest|RunEvent|registerSessionHandlers|startRunViaSocket|resumeSession|tool\\.started|tool\\.completed|applyResponseStreamEvent|flushResponseRunToDb|PluginManager|providesTools|listHermesPlugins" packages/client/src packages/server/src
```

已分类的常用入口：

- [x] session / run / SSE：先看 `packages/client/src/api/hermes/chat.ts`、`packages/server/src/routes/hermes/chat-run.ts`、`packages/server/src/services/hermes/chat-run-socket.ts`。
- [x] session 真相恢复：先看 `packages/server/src/db/hermes/session-store.ts`、`packages/server/src/db/hermes/sessions-db.ts`、`packages/server/src/services/hermes/session-sync.ts`。
- [x] 面板组件分层：先看 `packages/client/src/views/hermes/ChatView.vue`、`packages/client/src/components/hermes/chat/ChatPanel.vue`、`ChatInput.vue`、`MessageList.vue`、`MessageItem.vue`。
- [x] tool event：先看 `packages/client/src/stores/hermes/chat.ts`、`packages/client/src/components/hermes/chat/MessageItem.vue`、`packages/server/src/db/hermes/conversations-db.ts`。
- [x] plugin / skill 清单：先看 `packages/client/src/api/hermes/plugins.ts`、`packages/client/src/api/hermes/skills.ts`、`packages/server/src/routes/hermes/plugins.ts`、`packages/server/src/routes/hermes/skills.ts`、`packages/server/src/services/hermes/plugins.ts`。

| mnote 任务 | 参考文件 | 只参考什么 | 不采用什么 |
| --- | --- | --- | --- |
| Hermes API client 合同 | `packages/client/src/api/hermes/chat.ts`、`packages/client/src/api/hermes/sessions.ts`、`packages/client/src/api/hermes/conversations.ts` | chat run、session detail、conversation list/detail 的请求和响应形状 | 不直接复用 TS client，不让浏览器绕过 mnote-web proxy |
| Hermes proxy / route 形态 | `packages/server/src/routes/hermes/chat-run.ts`、`packages/server/src/routes/hermes/sessions.ts`、`packages/server/src/routes/hermes/proxy.ts`、`packages/server/src/routes/hermes/proxy-handler.ts` | 服务端 route 如何接收 run、session、proxy 请求以及错误透传边界 | 不把 Hermes server route 复制进 mnote；mnote 只做同源薄代理 |
| session 真相与恢复 | `packages/server/src/db/hermes/session-store.ts`、`packages/server/src/db/hermes/sessions-db.ts`、`packages/server/src/db/hermes/conversations-db.ts`、`packages/server/src/services/hermes/conversations.ts`、`packages/server/src/services/hermes/session-sync.ts` | session/message/conversation 的存储、搜索、恢复、thread/lineage 摘要 | 不在 mnote 里重建这些表或复制聊天历史 |
| usage / model 真相 | `packages/server/src/db/hermes/usage-store.ts`、`packages/client/src/stores/hermes/usage.ts`、`packages/client/src/stores/hermes/models.ts`、`packages/client/src/components/layout/ModelSelector.vue` | usage、model selection、model display 的字段和展示语义 | 不在 mnote page aggregate 保存 usage/model 真相 |
| chat 面板结构 | `packages/client/src/views/hermes/ChatView.vue`、`packages/client/src/components/hermes/chat/ChatPanel.vue`、`packages/client/src/components/hermes/chat/ChatInput.vue`、`packages/client/src/components/hermes/chat/MessageList.vue`、`packages/client/src/components/hermes/chat/MessageItem.vue`、`packages/client/src/components/hermes/chat/HistoryMessageList.vue`、`packages/client/src/components/hermes/chat/SessionListItem.vue` | session list、message list、输入框、消息项、历史消息的组件分层 | 不采用 Vue / Naive UI / Hermes 全屏布局；mnote 仍用 Leptos island 和 Wolai drawer 壳 |
| markdown / thinking 展示 | `packages/client/src/components/hermes/chat/MarkdownRenderer.vue`、`packages/client/src/utils/thinking-parser.ts`、`tests/client/chat-store-thinking.test.ts`、`tests/client/thinking-parser.test.ts` | markdown 渲染、`think/thinking/reasoning` 片段解析、streaming 中的 thinking 边界 | 不直接照搬样式；mnote 只实现页面 AI 抽屉需要的折叠展示 |
| stream / abort / resume | `packages/client/src/stores/hermes/chat.ts`、`packages/client/src/api/hermes/chat.ts`、`packages/server/src/routes/hermes/chat-run.ts`、`packages/server/src/services/hermes/chat-run-socket.ts` | run stream 事件、resume session room、abort started/completed、queue/server-working 状态 | 不强制采用 Socket.IO；mnote proxy 可用 SSE 或项目现有 stream 机制，但事件语义要对齐 |
| tool event 展示 | `packages/client/src/stores/hermes/chat.ts`、`packages/client/src/components/hermes/chat/MessageItem.vue`、`packages/client/src/components/hermes/chat/HistoryMessageList.vue`、`packages/server/src/db/hermes/conversations-db.ts` | `tool_call_id`、tool message、tool started/completed/failed 的归并与历史展示 | 不把 tool result 写入 mnote 正文；只展示 Hermes tool event |
| session 搜索 | `packages/client/src/components/hermes/chat/SessionSearchModal.vue`、`packages/client/src/composables/useSessionSearch.ts`、`tests/client/session-search.test.ts`、`tests/client/sidebar-search.test.ts` | 后续 session search 的交互和过滤语义 | 第一版可后置，不进入最小验收 |
| plugins / skills 列表 | `packages/client/src/api/hermes/plugins.ts`、`packages/client/src/api/hermes/skills.ts`、`packages/server/src/routes/hermes/plugins.ts`、`packages/server/src/routes/hermes/skills.ts`、`packages/server/src/services/hermes/plugins.ts`、`packages/client/src/components/hermes/skills/SkillList.vue`、`packages/client/src/components/hermes/skills/SkillDetail.vue` | Hermes 如何表达 plugin/skill 清单、启停和详情 | 不采用 Hermes skills 管理页面；mnote 只暴露 `mnote.*` tool manifest |
| 不属于 mnote 页面 AI 第一版 | `packages/client/src/views/hermes/ChannelsView.vue`、`JobsView.vue`、`FilesView.vue`、`TerminalView.vue`、`GroupChatView.vue`、`SettingsView.vue`、`ProfilesView.vue`、`LogsView.vue`、`UsageView.vue` | 仅作为边界参考，说明这些是 Hermes 管理台能力 | 不进入页面 AI 抽屉第一版 |

---

## 2. 总体验收标准

7-4 完成时必须同时满足：

- [x] 页面 AI 抽屉打开后创建或恢复的是 Hermes session。
- [x] Hermes session 存储里能看到页面 AI 的消息历史。
- [x] mnote 本地不保存聊天消息真相，只保存业务写入 audit、artifact、edge、page/body/title/options 结果。
- [x] 页面 AI 发送消息后，事件流来自 Hermes run，而不是旧 `/api/ai-agent/run` provider / fallback 分支。
- [x] tool call 展示来自 Hermes tool event；真实 Hermes upstream run 已触发 `mnote.page.get`，刷新后从 Hermes session detail 恢复。
- [x] Hermes 至少能调用一个只读 mnote 工具读取当前页面。
- [x] Hermes 至少能调用一个写入 mnote 工具，经 Rust runtime 写回当前页面正文或创建 artifact。
- [x] 页面刷新后，AI 会话从 Hermes 恢复，而不是从 mnote 本地 state 恢复。
- [x] 旧 `provider=hermes` 502 不再出现在新页面 AI 主链。
- [x] `rg` 检查活跃设计稿与代码注释不再把 `mnote-cli` 写成页面 AI 唯一长期执行面；命中已逐条归类为历史/兼容/已覆盖。

最终验收命令建议：

```bash
cd /mnt/Data1T/mnote
rg -n "mnote-cli.*唯一|唯一长期 agent|页面 AI.*mnote-cli|provider=hermes" design rust wolai-frontend --glob '*.md' --glob '*.rs' --glob '*.ts' --glob '*.tsx'
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js
MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-smoke.js
```

通过标准：

- [x] `rg` 只允许命中 `design/old/` 或明确标注“历史/兼容/已覆盖”的段落。
- [x] `task-hermes-page-ai-smoke.js` 证明页面 AI 使用 Hermes session / run / stream，并验证刷新后从 Hermes session detail 恢复。
- [x] `task-hermes-page-ai-tool-smoke.js` 证明 Hermes tool call 能回到 mnote Rust runtime 并产生可读业务结果。

2026-05-14 验证记录：

- [x] `cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web hermes_ -- --nocapture`：15 passed。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-smoke.js`：通过，捕获 `session -> session-detail -> run -> events -> session-detail`，渲染 `mnote.page.get` tool event，刷新恢复命中 Hermes session detail 2 次。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-tool-smoke.js`：通过，`mnote.page.get` 返回标题、正文摘要和 read audit。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-writeback-smoke.js`：通过，`mnote.page.save` 写入走 `page.body.save`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-title-options-smoke.js`：通过，标题走 `page.head.updateTitle`，页面设置走 `page.layout.updateOptions`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-artifact-smoke.js`：通过，summary / ai_note 都走 `tree.node.create`。
- [x] 早期临时 `3019` 验证曾确认旧 `/api/ai-agent/run` 不再静默 fallback；最终正式 `3000` 验收已由 Task K/M 覆盖，当前稳定退场码为 `410 legacy_ai_agent_run_retired`。
- [x] 上述临时 `3019` 证据已被正式 `http://127.0.0.1:3000` 全矩阵复跑覆盖；最终以 Task M 的 8 个 `3000` smoke 证据为准。
- [x] 追加验证：`task-hermes-page-ai-writeback-smoke.js`、`task-hermes-page-ai-title-options-smoke.js`、`task-hermes-page-ai-artifact-smoke.js` 已断言 `audit.commandId == result.commandId`，临时 `3019` 通过。
- [x] 追加验证：临时 `3019` 日志已输出 `mnote Hermes tool call started/completed`，字段包含 `trace_id/session_id/run_id/tool_call_id/tool_name/workspace_id/document_id/actor_id/effect`。
- [x] 追加验证：`MNOTE_UI_BASE_URL=http://127.0.0.1:3019 node scripts/task-hermes-page-ai-mobile-smoke.js` 通过，390px 窄屏下 drawer / panel / document 均无横向溢出。
- [x] 追加验证：`task-hermes-page-ai-writeback-smoke.js` 已在 dryRun 后立即读取 `/api/documents/content`，确认写入标记不存在；随后正式写入再确认标记存在。
- [x] 追加验证：`hermes_tools_write_tools_require_auth` 已覆盖未认证写工具返回 401。
- [x] 追加验证：`task-hermes-page-ai-writeback-smoke.js` 已用同一 `idempotencyKey` 重试正式写入，断言返回同一 `result.commandId/audit.commandId`；临时 `3019` 日志出现 `mnote Hermes tool call idempotency replay`。
- [x] 追加验证：`task-hermes-page-ai-title-options-smoke.js` 已打开真实文档页，确认刷新后标题输入、breadcrumb/current title、`data-page-wide-layout=true`、`data-page-small-text=true` 均生效。
- [x] 追加验证：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js` 通过，`tree_1778720870666_1` 标题更新为 `TEST-HERMES-AI-title-updated-mp4shbjq`，页头 / breadcrumb/current title / sidebar 均一致。
- [x] 追加验证：`task-hermes-page-ai-title-options-smoke.js` 已断言 `pageFont` 返回 `ignoredOptions=["pageFont"]` 与 `warningCodes=["page_option_not_wired"]`，不进入 `page.layout.updateOptions` 写入 payload。
- [x] 追加验证：`task-hermes-page-ai-title-options-smoke.js` 已打开页面 AI 面板，确认 `data-mnote-page-ai-session-owner=hermes`，mnote localStorage 只保存 Hermes `activeSessionId`，不保存或驱动 mnote 页面标题真相。
- [x] 追加验证：`task-hermes-page-ai-title-options-smoke.js` 已验证 `mnote.page.update_title` dryRun 后 meta 不变化，并验证同一 `idempotencyKey` 重试返回同一 `commandId`。
- [x] 追加验证：`task-hermes-page-ai-artifact-smoke.js` 已验证 summary 同 key 重试返回同一 `commandId/artifactDocumentId`，ai_note 第二次创建得到独立 `artifactDocumentId`，并验证工具结果里的 `referenceEdge.from/to/kind`。
- [x] 追加验证：`task-hermes-page-ai-audit-smoke.js` 已调用 `mnote.page.get` 与 `mnote.page.save`，并通过 `/api/hermes/tools/mnote/audit?traceId=...` 反查 `started/completed` 事件，写工具 audit 可串到 Rust `commandId`，且不包含完整正文内容。

---

## 3. Task A：运行态基线与旧 502 复现

目标：

> 先固定当前问题和旧链入口，避免后续改动时把“没有复现”误认为“已经修好”。

建议修改范围：

- 新增或复用 smoke：
  - `scripts/task-hermes-page-ai-baseline-smoke.js`
- 只读记录：
  - `rust/crates/mnote-web/src/routes/**`
  - `wolai-frontend/src/**/ai-agent/**`
  - `design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`

执行步骤：

- [x] 启动当前前后端，确保测试入口可访问。
- [x] 用真实测试账号登录。历史执行时使用旧 Auth 后端；当前默认应使用 SQLite control-plane Auth / session。
- [x] 打开任意测试页面，点击右下角页面 AI。
- [x] 发送一条只读问题，例如“概括当前页面标题和第一段”。
- [x] 记录当前请求是否仍命中旧 `/api/ai-agent/run`。
- [x] 记录是否出现 `provider=hermes` 相关 502、`ai_provider_bridge_unavailable` 或旧 fallback 文案。
- [x] 将证据写入本 task 对应 bug 或执行记录，不修改业务逻辑。

验收标准：

- [x] 有一份可复跑 smoke 或手动执行记录，明确当前页面 AI 主请求 URL。
- [x] 能区分以下三类状态：
  - 旧 `/api/ai-agent/run` 仍被页面 AI 调用。
  - 页面 AI 已调用 Hermes proxy，但 proxy 未接通。
  - 页面 AI 已调用 Hermes proxy 且 session/run 可恢复。
- [x] 若仍出现 502，记录请求 URL、响应 body、mnote-web 日志时间戳和页面截图。
- [x] 不把本 task 的 502 修复写进同一个提交；本 task 只做基线。

---

## 4. Task B：冻结 Hermes client proxy 合同

目标：

> 先冻结浏览器到 mnote-web 的同源 Hermes client proxy 合同，防止 Leptos 面板直接绑定 Hermes 私有 API 或暴露 key。

建议修改范围：

- 新增设计/协议文档：
  - `design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md`
- 后续代码位置建议：
  - `rust/crates/mnote-web/src/routes/hermes_client.rs`
  - `rust/crates/mnote-web/src/routes/mod.rs`
  - `rust/crates/mnote-web/src/config.rs`

合同路径第一版：

- `GET /api/hermes/client/sessions`
- `POST /api/hermes/client/sessions`
- `GET /api/hermes/client/sessions/{session_id}`
- `POST /api/hermes/client/runs`
- `GET /api/hermes/client/events/{run_id}`
- `POST /api/hermes/client/runs/{run_id}/abort`
- `GET /api/hermes/client/models`
- `GET /api/hermes/client/tools`

必须统一的请求字段：

- `workspaceId`
- `documentId`
- `sessionId`
- `message`
- `pageContext`
- `selectedBlockId`
- `selectedText`
- `traceId`

必须统一的响应字段：

- `sessionId`
- `runId`
- `messageId`
- `events[]`
- `error.code`
- `error.message`
- `traceId`

执行步骤：

- [x] 写明每个 proxy route 的输入输出 JSON 示例。
- [x] 写明 proxy 只做 auth、同源安全、上下文注入和错误码标准化。
- [x] 写明 proxy 不保存 session/message/tool event。
- [x] 写明 Hermes API key 或 token 只存在服务端环境变量中。
- [x] 写明 `pageContext` 是运行输入，不是 Hermes session 的长期事实源。
- [x] 写明旧 `/api/ai-agent/run` 与新 proxy 的并存期规则。

验收标准：

- [x] 合同文档里每个 route 都有请求/响应示例。
- [x] 文档明确禁止浏览器直接持有 Hermes API key。
- [x] 文档明确禁止 mnote 保存 Hermes 聊天历史。
- [x] 文档明确旧 `/api/ai-agent/run` 不是新 Hermes 面板主代理。
- [x] 后续实现者不需要读 Hermes Web UI 源码也能知道 mnote 侧 proxy 的稳定合同。

---

## 5. Task C：实现 Hermes client proxy 最小只读链

目标：

> 让页面 AI 可以通过 mnote-web 同源代理创建/恢复 Hermes session，并发起一个无工具写入的只读 run。

建议修改范围：

- 新增：
  - `rust/crates/mnote-web/src/routes/hermes_client.rs`
- 修改：
  - `rust/crates/mnote-web/src/routes/mod.rs`
  - `rust/crates/mnote-web/src/config.rs`
  - `rust/crates/mnote-web/src/error.rs`
- 测试：
  - `rust/crates/mnote-web/tests/hermes_client_proxy.rs` 或同 crate 现有 route 测试文件

执行步骤：

- [x] 先写 route 测试：未登录请求返回 401 或项目统一 auth 错误。
- [x] 写 route 测试：未配置 Hermes upstream 时返回稳定错误码 `hermes_client_unconfigured`。
- [x] 写 route 测试：`POST /api/hermes/client/sessions` 只代理 session 创建，不写 mnote 数据。
- [x] 写 route 测试：`POST /api/hermes/client/runs` 会带上 `workspaceId/documentId/pageContext/traceId`。
- [x] 实现最小 upstream client，先只支持 session create、session get、run create。
- [x] 统一错误响应：Hermes 连接失败、401、429、5xx 必须映射成可展示的错误码。
- [ ] 记录日志字段：`traceId/sessionId/runId/documentId/workspaceId`。

验收标准：

- [x] `cargo test -p mnote-web hermes_client` 通过。
- [x] 未配置 Hermes 时，页面 AI 不出现 502，而是得到稳定 `hermes_client_unconfigured`。
- [x] 配置 Hermes upstream 后，session create 和 run create 请求能从 mnote-web 代理到 Hermes。
- [x] mnote 数据库、page aggregate、Convex 页面内容没有新增聊天消息字段。
- [x] 网络请求中浏览器看不到 Hermes API key。

---

## 6. Task D：冻结 mnote Hermes plugin tool 合同

目标：

> 先定义 Hermes 看到的 mnote 工具清单和工具结果格式，避免工具从页面前端私有函数开始长出来。

建议新增文档：

- `design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`

第一批工具：

- `mnote.page.get`
- `mnote.page.save`
- `mnote.page.update_title`
- `mnote.page.update_options`
- `mnote.artifact.create_summary`
- `mnote.artifact.create_ai_note`

第二批工具：

- `mnote.tree.create`
- `mnote.tree.move`
- `mnote.search.documents`
- `mnote.kernel.attach_reference`

统一入参：

- `workspaceId`
- `documentId`
- `actorId`
- `sessionId`
- `runId`
- `toolCallId`
- `traceId`
- `idempotencyKey`
- `dryRun`
- `capabilityScope`

统一出参：

- `ok`
- `toolName`
- `toolCallId`
- `traceId`
- `result`
- `audit`
- `error`

执行步骤：

- [x] 为每个第一批工具写 JSON schema。
- [x] 为每个第一批工具写成功响应示例。
- [x] 为每个第一批工具写失败响应示例。
- [x] 写明权限校验点：登录、workspace member、页面读、页面写、artifact 写。
- [x] 写明幂等规则：同一 `idempotencyKey` 重试不得重复创建 artifact。
- [x] 写明 `dryRun=true` 时只能返回计划和 diff，不得写入。
- [x] 写明 plugin 内部可以暂时调用 `mnote-cli` JSON adapter，但对 Hermes 暴露的名字必须是 `mnote.*`。

验收标准：

- [x] 合同文档覆盖所有第一批工具。
- [x] 每个写工具都有 `dryRun`、`idempotencyKey`、权限失败、业务失败示例。
- [x] 文档明确 tool 结果最终来自 Rust runtime / kernel。
- [x] 文档明确 Hermes plugin 不直接写 Convex。
- [x] 文档明确 `mnote-cli` 是内部 adapter，不是 Hermes 看到的长期 tool 名称。

---

## 7. Task E：实现 mnote tool manifest 与只读工具

目标：

> 先让 Hermes 能发现 mnote 工具，并调用 `mnote.page.get` 读取当前页面。

建议修改范围：

- 新增：
  - `rust/crates/mnote-web/src/routes/hermes_tools.rs`
  - `rust/crates/mnote-web/src/hermes_tools/mod.rs`
  - `rust/crates/mnote-web/src/hermes_tools/manifest.rs`
  - `rust/crates/mnote-web/src/hermes_tools/page.rs`
- 修改：
  - `rust/crates/mnote-web/src/routes/mod.rs`
  - `rust/crates/bridge-runtime/src/lib.rs` 只在缺少正式 query 时补窄入口
- 测试：
  - `rust/crates/mnote-web/tests/hermes_tools.rs`

建议 route：

- `GET /api/hermes/tools/mnote/manifest`
- `POST /api/hermes/tools/mnote/call`

执行步骤：

- [x] 写 manifest 测试：返回第一批工具名称、schema version、capability scope。
- [x] 写 `mnote.page.get` 测试：未登录失败。
- [ ] 写 `mnote.page.get` 测试：无 workspace 权限失败。
- [x] 写 `mnote.page.get` 测试：有权限时返回当前 page aggregate 摘要。
- [x] 实现 manifest route。
- [x] 实现统一 tool call dispatcher，只接 `mnote.page.get`。
- [x] 将 `mnote.page.get` 接到现有 Rust runtime / page aggregate query。

验收标准：

- [x] `cargo test -p mnote-web hermes_tools` 通过。
- [x] `GET /api/hermes/tools/mnote/manifest` 返回稳定 `mnote.page.get` schema。
- [x] `POST /api/hermes/tools/mnote/call` 调用 `mnote.page.get` 返回当前页面标题、正文摘要、page options、可用 block 摘要。
- [ ] 权限失败不会泄露页面标题或正文。
- [x] 工具返回中包含 `traceId/toolCallId/sessionId`。

---

## 8. Task F：Leptos Hermes 面板最小只读 UI

目标：

> 在保留 Wolai 右下角入口和右侧抽屉壳的前提下，把页面 AI 面板改为调用 Hermes client proxy。

建议修改范围：

- Leptos / Rust SSR 侧按当前真实结构定位：
  - `rust/crates/mnote-web/src/ssr/**`
  - `rust/crates/mnote-web/src/routes/web_shell.rs`
  - 页面内 island 挂载资源所在目录
- 若仍需 React compat，只能作为旧 panel 参考，不得扩展旧执行链：
  - `wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx`
- smoke：
  - `scripts/task-hermes-page-ai-smoke.js`

第一版 UI 子集：

- session 创建/恢复
- message list
- chat input
- streaming delta
- reasoning 展开
- tool started / completed 展开
- error / retry / abort
- model selector 可先只读展示默认模型

执行步骤：

- [x] 写 smoke：打开页面 AI 后，不允许发送请求到 `/api/ai-agent/run`。
- [x] 写 smoke：打开页面 AI 后，会请求 `/api/hermes/client/sessions`。
- [x] 写 smoke：发送消息后，会请求 `/api/hermes/client/runs`。
- [x] 写 smoke：页面刷新后，面板可从 Hermes session 恢复消息。
- [x] 实现 Leptos 面板数据层，只保存 UI 临时状态，不保存聊天真相。
- [x] 接入 session create / restore。
- [x] 接入 run create / event stream。
- [ ] 接入 abort / retry 的最小状态。
- [x] 保留右下角入口、右侧 drawer、Esc / close 行为与 `5-11` 证据一致。

验收标准：

- [x] `node scripts/task-hermes-page-ai-smoke.js` 通过。
- [x] 页面 AI 主链不再请求 `/api/ai-agent/run`。
- [x] 页面 AI 消息刷新后来自 Hermes session。
- [x] mnote 本地页面 state 里没有完整聊天消息数组。
- [ ] 抽屉入口、关闭语义、移动端不溢出继续符合 `5-11` 的历史 Wolai 对齐要求。
- [x] Hermes 不可用时展示稳定错误态，不出现 502 空白或旧 `page_ai_failed_502`。

---

## 9. Task G：接入 Hermes tool event 展示与只读工具调用

目标：

> 让 Hermes run 调用 `mnote.page.get` 时，页面 AI 能展示 tool started / completed，并把结果作为 Hermes 消息链的一部分呈现。

建议修改范围：

- `rust/crates/mnote-web/src/routes/hermes_client.rs`
- `rust/crates/mnote-web/src/routes/hermes_tools.rs`
- Leptos 面板 island 相关文件
- `scripts/task-hermes-page-ai-tool-smoke.js`

执行步骤：

- [x] 写 smoke：发送“读取当前页面标题和页面设置”，期望出现 `mnote.page.get` tool started。
- [x] 写 smoke：同一次 run 出现 `mnote.page.get` tool completed。
- [ ] 写 smoke：tool result 中的标题与当前页头标题一致。
- [x] 实现 tool event 渲染：started、completed、failed 三态。
- [ ] 实现 tool result 折叠展示，默认只显示 tool 名和摘要。
- [x] 确保 tool result 不被写入 mnote 页面正文。
- [x] 确保 Hermes session 中保留 tool event，刷新后可恢复。

验收标准：

- [x] `node scripts/task-hermes-page-ai-tool-smoke.js` 通过。
- [ ] 工具事件来自真实 Hermes upstream run，而不是前端本地伪造。
- [ ] `mnote.page.get` 权限失败时，UI 显示 tool failed，正文不泄露。
- [x] 刷新页面后 tool event 仍从 Hermes session 恢复。
- [x] mnote page aggregate 不包含 tool event 历史。

---

## 10. Task H：接入正文写入工具 `mnote.page.save`

目标：

> 让 Hermes 可以通过 mnote plugin 对当前页正文做最小写入，写入仍走正式 `page.body.save` 链。

建议修改范围：

- `rust/crates/mnote-web/src/hermes_tools/page.rs`
- `rust/crates/bridge-runtime/src/lib.rs` 仅补必要正式 command adapter
- 页面保存相关 route / command adapter
- smoke：
  - `scripts/task-hermes-page-ai-writeback-smoke.js`

执行步骤：

- [x] 写 tool contract 测试：`mnote.page.save` 必须要求 `documentId`、`idempotencyKey`、`dryRun`。
- [x] 写 dryRun 测试：`dryRun=true` 返回 diff，不写入。
- [x] 写权限失败测试：未认证时不进入页面写链。
- [x] 写幂等测试：同一 `idempotencyKey` 重试不重复执行写链。
- [x] 实现 `mnote.page.save` 到 `page.body.save` 的 adapter。
- [ ] 在 Hermes 面板里对写工具结果展示 diff 摘要。
- [x] smoke 执行：让 AI 在当前测试页面写入一段带测试前缀的文本。
- [x] smoke 读取 `/api/documents/content` 或当前正式内容接口，确认刷新后文本存在。

验收标准：

- [x] dryRun 不改变页面内容。
- [x] 未认证不进入写链。
- [x] 同一幂等键不会重复写入。
- [ ] 正式写入后，主编辑区 island 能立即回显。
- [x] 刷新后内容仍存在。
- [x] 写入链路日志包含 `sessionId/runId/toolCallId/traceId/documentId/actor`。
- [x] 写入不经过旧 `/api/ai-agent/run`。

---

## 11. Task I：接入标题与页面设置工具

目标：

> 把 AI 修改标题和页面设置收口到同一组 Page Aggregate command family，而不是靠面板本地副作用。

建议修改范围：

- `rust/crates/mnote-web/src/hermes_tools/page.rs`
- `rust/crates/bridge-runtime/src/lib.rs`
- `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md` 仅回填完成证据
- smoke：
  - `scripts/task-hermes-page-ai-title-options-smoke.js`

执行步骤：

- [x] 写 `mnote.page.update_title` dryRun / permission / idempotency 测试。
- [x] 写 `mnote.page.update_options` dryRun / permission / wired-only 字段测试。
- [x] 实现标题工具到 `page.head.updateTitle`。
- [x] 实现页面设置工具到 `page.layout.updateOptions`。
- [x] 禁止写入 `runtimeSupport !== "wired"` 的页面设置字段。
- [x] smoke 修改当前测试页标题，确认页头与 breadcrumb/current title 一致。
- [x] smoke 修改 `smallText` 或 `wideLayout`，确认主编辑区 page shell 属性变化。

验收标准：

- [x] 标题修改后页头、breadcrumb、sidebar、刷新后标题一致。
- [x] 页面设置修改只允许 wired 字段。
- [x] planned / ui_only 字段返回明确错误或 dryRun 警告。
- [x] AI 面板不维护独立标题状态。
- [x] 所有写入都经 Rust runtime / Page Aggregate command family。

---

## 12. Task J：接入结构化 Artifact 工具

目标：

> 落地 `7-2` 的 `summary node / ai_note node / reference edge`，触发方改为 Hermes tool call。

建议修改范围：

- `rust/crates/mnote-web/src/hermes_tools/artifact.rs`
- `rust/crates/bridge-runtime/src/lib.rs`
- `rust/crates/core-protocol/src/**` 若缺少正式类型再补
- smoke：
  - `scripts/task-hermes-page-ai-artifact-smoke.js`

执行步骤：

- [x] 写 `mnote.artifact.create_summary` schema 测试。
- [x] 写 `mnote.artifact.create_ai_note` schema 测试。
- [x] 写 summary 单例更新测试：同一页面重复创建 summary 不生成多个 summary node。
- [x] 写 ai_note 多次创建测试：每次生成独立 ai_note node。
- [x] 写 reference edge 测试：artifact 与当前页面之间有可查询 reference edge。
- [x] 实现工具到 Rust runtime / kernel。
- [x] 页面 AI 面板可提供 `创建 Summary` / `创建 AI Note` 快捷入口，但入口只发送 Hermes intent。
- [x] smoke 验证 `AI Artifacts` projection-only 分组可见。

2026-05-14 J1 执行证据：

- [x] 修正 `rust/crates/bridge-runtime/src/lib.rs`：从 artifact 文档命名与父子关系派生 `metadata.kind="ai_artifact_reference"` 的 `source_of` kernel edge，并在 file-tree projection `meta.aiArtifacts` 中标记 `projectionOnly=true`、`kernelNodeId=null`。
- [x] 新增 bridge-runtime 单测 `kernel_edges_list_exposes_ai_artifact_reference_edges` 与 `file_tree_projection_marks_ai_artifacts_group_as_projection_only`。
- [x] 验证命令：`cd rust && cargo test -p bridge-runtime ai_artifact -- --nocapture`：2 passed。
- [x] 验证命令：`cd rust && cargo build -p mnote-web`：通过；正式 `3000` 已重启到新二进制，PID `2043001`。
- [x] 扩展 `scripts/task-hermes-page-ai-artifact-smoke.js`：调用 `/api/kernel/edges` 查询 summary / ai_note 的 `ai_artifact_reference`，调用 `/api/tree/projections/file` 查询 `meta.aiArtifacts.projectionOnly=true`，并回查 artifact audit。
- [x] 修正 `rust/crates/mnote-web/src/ssr/pages/layout.rs` 与 `rust/crates/mnote-web/src/ssr/styles.rs`：页面 AI 抽屉提供 `创建 Summary` / `创建 AI Note` 快捷入口，点击后只调用 `sendPageAiMessage(...)` 发送 Hermes intent。
- [x] 验证命令：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js`：通过；最终复跑测试页 `tree_1778721933687_1`，summary `summary_tree_1778721933687_1`，ai_note `ai_note_tree_1778721933687_1_req_1778721933785_11`、`ai_note_tree_1778721933687_1_req_1778721933813_13`，`referenceEdgeCount=6`，`auditEventCount=6`；快捷入口发送的 Hermes intent 分别包含 `mnote.artifact.create_summary` 与 `mnote.artifact.create_ai_note`，且页面路由已禁止直连 `/api/hermes/tools/mnote/call`。

验收标准：

- [x] artifact 创建不绕过 Hermes tool call。
- [x] artifact 创建不绕过 Rust runtime / kernel。
- [x] `AI Artifacts` 仍是 projection-only 分组，不是真实 kernel node。
- [x] summary node 可重复更新但不重复创建。
- [x] ai_note node 每次新建。
- [x] reference edge 可通过 kernel query 或 projection 验证。
- [x] artifact 写入 audit 包含 Hermes `sessionId/runId/toolCallId`。

---

## 13. Task K：退役旧页面 AI 主执行链

目标：

> 新 Hermes 面板通过后，旧 `/api/ai-agent/run` 不再作为页面 AI 主入口。

建议修改范围：

- `rust/crates/mnote-web/src/routes/**`
- `wolai-frontend/src/app/api/ai-agent/run/route.ts`
- `wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx`
- `design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md`

执行步骤：

- [x] 全仓搜索页面 AI 发送路径。
- [x] 删除或禁用页面 AI 对 `/api/ai-agent/run` 的主路径调用。
- [x] 保留 legacy endpoint 时，响应必须明确 `legacy_ai_agent_run_retired` 或项目统一退场码。
- [x] 删除 `provider=hermes` 作为旧 endpoint provider/fallback 的语义。
- [x] 更新旧 smoke：不再期待 `/api/ai-agent/run -> mnote-cli`。
- [x] 保留历史 smoke 到 `old` 或改名为 legacy guard。

2026-05-14 K 执行证据：

- [x] 修正 `rust/crates/mnote-web/src/routes/compat.rs`：`POST /api/ai-agent/run` 不再进入 `mnote-cli host`，统一返回 `410 legacy_ai_agent_run_retired`，响应头 `x-mnote-ai-execution-owner=legacy-ai-agent-run-retired`。
- [x] 更新 compat 单测：`direct_ai_agent_run_returns_legacy_retired_guard`、`explicit_agent_provider_returns_legacy_retired_guard`、`explicit_hermes_provider_fails_instead_of_using_legacy_next_or_direct_bridge`。
- [x] 验证命令：`cd rust && cargo test -p mnote-web ai_agent_run -- --nocapture`：1 passed。
- [x] 验证命令：`cd rust && cargo test -p mnote-web explicit_ -- --nocapture`：2 passed。
- [x] 验证命令：`cd rust && cargo build -p mnote-web`：通过；正式 `3000` 已重启到新二进制，PID `2108896`。
- [x] 验证命令：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-retirement-guard.js`：通过，status `410`，code `legacy_ai_agent_run_retired`，owner `legacy-ai-agent-run-retired`。
- [x] 默认退役历史 smoke：`task155-e27-ai-edit-smoke.js`、`task156-e27-ai-writeback-smoke.js`、`task178-page-ai-local-subtree-context-smoke.js`、`task052-ai-tools-runtime-smoke.js`、`task161-wolai-page-ai-shell-smoke.js`、`task111-phase7-document-ai-online-smoke.js` 已移入本机 gitignored `recycle/scripts/retired-ai-agent-run-smokes/`，历史版本默认输出 `{ retired: true }`，不再期待旧 `/api/ai-agent/run -> mnote-cli` 成功；如需历史对照，必须显式设置 `MNOTE_ALLOW_RETIRED_AI_AGENT_RUN_SMOKE=1`。
- [x] legacy 调用方清点：`wolai-frontend/src/components/ai-agent/AiAgentPanel.tsx`、`wolai-frontend/src/components/editor/blocks/MindmapAiAgentPanel.runtime.tsx`、`wolai-frontend/src/components/onlyoffice/OnlyOfficeAiAgentPanel.runtime.tsx`、`wolai-frontend/src/app/api/mindmap-ai/expand-node/route.ts` 仍是旧域/兼容调用点，不属于当前 mnote-web 页面 AI 主链；若被调用会命中 `legacy_ai_agent_run_retired` guard，后续按各自 domain 另拆 Hermes plugin / Rust bridge 迁移。
- [x] 活跃设计口径同步：`5-6`、`5-9`、`10-review` 已改为历史/已覆盖/legacy guard 说明，不再把 `/api/ai-agent/run` 写作页面 AI 长期入口。

验收标准：

- [x] 新页面 AI 主链无 `/api/ai-agent/run` 请求。
- [x] 访问旧 `/api/ai-agent/run` 不会静默 fallback 到 Hermes、Codex、旧 orchestrator。
- [x] `provider=hermes` 不再产生新页面 AI 主链 502。
- [x] 活跃文档不再把 `/api/ai-agent/run` 描述为页面 AI 长期入口。
- [x] legacy 调用方清单为空，或全部有明确退场说明。

---

## 14. Task L：权限、审计与可观测性闭环

目标：

> 让 Hermes 调用 mnote 工具后的每一次业务影响都可审计、可追踪、可复盘。

建议修改范围：

- `rust/crates/mnote-web/src/hermes_tools/**`
- `rust/crates/bridge-runtime/src/**`
- audit / event log 相关 crate 或 route
- smoke：
  - `scripts/task-hermes-page-ai-audit-smoke.js`

执行步骤：

- [x] 定义统一 trace 字段：`traceId/sessionId/runId/toolCallId/documentId/workspaceId/actorId/toolName`。
- [x] 所有 tool call 开始时记录 intent。
- [x] 所有成功写入记录 result 和 command id。
- [x] 所有失败记录错误码，不记录完整隐私正文。
- [x] smoke 执行一次 `mnote.page.get` 和一次写工具。
- [x] smoke 从日志或审计接口确认两次 tool call 都可追踪。

2026-05-14 L 执行证据：

- [x] 修正 `rust/crates/mnote-web/src/routes/hermes_tools.rs`：`audit_push` 同步写入内存缓存与 JSONL 持久化落点，默认路径 `tmp/mnote-hermes-tool-audit.jsonl`，可用 `MNOTE_HERMES_TOOL_AUDIT_LOG` 覆盖；`GET /api/hermes/tools/mnote/audit?persistedOnly=true` 只读取持久化审计。
- [x] workspace 上下文冲突现在也会写入 `started -> failed` 审计链，失败审计只包含 trace / tool / actor / workspace / document / status / message，不写入页面标题或正文。
- [x] 扩展 `scripts/task-hermes-page-ai-audit-smoke.js`：执行 `mnote.page.get`、`mnote.page.save`、workspace 权限失败三类调用；分别查询内存 audit 与 `persistedOnly=true` audit；断言写工具持久化 audit 串到 Rust `commandId`，权限失败持久化 audit 不包含正文 marker 或页面标题。
- [x] 验证命令：`cd rust && cargo test -p mnote-web hermes_tools_ -- --nocapture`：9 passed。
- [x] 验证命令：`cd rust && cargo build -p mnote-web`：通过；正式 `3000` 已重启到新二进制，PID `2175265`。
- [x] 验证命令：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js`：通过；测试页 `tree_1778723140835_1`，写命令 `page_body_save_req_1778723140928_9`，`writePersistedPhases=["started","completed"]`，`deniedPersistedPhases=["started","failed"]`。

验收标准：

- [x] 每个 tool call 都有稳定 trace。
- [x] 写工具能追踪到最终 Rust command。
- [x] 失败不会泄露无权限页面内容。
- [x] 日志可以把页面 AI 面板请求、Hermes run、mnote tool call、Rust command 串起来。
- [x] 审计只保存业务影响，不保存完整 Hermes 聊天历史。

---

## 15. Task M：端到端验收矩阵

目标：

> 用一组固定 smoke 证明新主线能覆盖只读、写正文、写标题/设置、artifact 和旧链退役。

必须具备的 smoke：

- [x] `scripts/task-hermes-page-ai-smoke.js`
- [x] `scripts/task-hermes-page-ai-tool-smoke.js`
- [x] `scripts/task-hermes-page-ai-writeback-smoke.js`
- [x] `scripts/task-hermes-page-ai-title-options-smoke.js`
- [x] `scripts/task-hermes-page-ai-artifact-smoke.js`
- [x] `scripts/task-hermes-page-ai-retirement-guard.js`
- [x] `scripts/task-hermes-page-ai-mobile-smoke.js`
- [x] `scripts/task-hermes-page-ai-audit-smoke.js`

执行顺序：

- [x] 只读 session/run smoke。
- [x] 只读 tool smoke。
- [x] 正文写入 smoke。
- [x] 标题与页面设置 smoke。
- [x] artifact smoke。
- [x] 旧链退役 guard。
- [x] 移动端 / 窄屏抽屉 smoke。
- [x] 刷新恢复 smoke。

2026-05-14 M 执行证据：

- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js`：通过；`tree_1778723249255_3`，session `mnote_smoke_mp4twavi`，run `run_smoke_mp4twavi`，`sessionDetailHits=2`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-smoke.js`：通过；`tree_1778723260375_5`，工具 `mnote.page.get`，标题 `TEST-HERMES-AI-tool-mp4twjgi`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-writeback-smoke.js`：通过；`tree_1778723271226_7`，marker `TEST-HERMES-AI-WRITEBACK-mp4twrtt`，command `page_body_save_req_1778723271849_379`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js`：通过；`tree_1778723295128_9`，标题 `TEST-HERMES-AI-title-updated-mp4txa9v`，`pageFont` 返回 `page_option_not_wired` warning。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js`：通过；`tree_1778723316873_11`，`referenceEdgeCount=6`，`meta.aiArtifacts.projectionOnly=true`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-retirement-guard.js`：通过；旧入口返回 `410 legacy_ai_agent_run_retired`。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-mobile-smoke.js`：通过；390px viewport 下 drawer/panel 均无横向溢出。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js`：通过；`tree_1778723372948_15`，写命令 `page_body_save_req_1778723373026_707`，持久化 audit 可查 `started/completed` 与权限失败 `started/failed`。

总体验收标准：

- [x] 所有 smoke 在真实 `http://127.0.0.1:3000` 上通过。
- [x] 使用默认真实测试账号，不使用 `MNOTE_DEV_AUTH=1` 伪登录作为正式验收。历史执行时使用旧 Auth 后端；当前默认应使用 SQLite control-plane Auth / session。
- [x] smoke 只操作本轮新建测试数据，测试数据前缀统一为 `TEST-HERMES-AI-<timestamp>`。
- [x] 测试结束后可定位创建的页面、artifact、edge、audit。
- [x] 任一 smoke 失败时，必须记录到 `bugs/` 对应分类，而不是在 checklist 中直接标 GREEN。

---

## 16. Task N：文档回填与 old 目录治理

目标：

> 代码主链切换后，设计目录继续反映真实状态，避免旧 CLI-first 口径回流。

2026-05-14 口径审计记录：

- [x] `find design/07-ai -maxdepth 3 -type f | sort` 已确认当前 07-ai 活跃结构为：`7-1`、`7-2`、`7-3`、`7-4`、`7-5`、`7-6` 在 `done/`；后续 Mini Hermes 控制面由 `design/07-ai/process/7-7-page-ai-mini-hermes-control-surface-v1.md` 承接。
- [x] `design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 仍保留为历史决策记录，并已标 `[recycle]`。
- [x] `design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md` 的 `mnote-cli` 命中均用于说明历史 CLI-first / 被覆盖 / 禁止继续采用的口径。
- [x] `design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md` 的 `mnote-cli` 与 `provider=hermes` 命中均用于迁移目标、legacy guard 或验收条件，不把它写成长期主线。
- [x] 活跃设计命中已收口：`5-6`、`5-9`、`10-review/04`、`10-review/06`、`1-1`、`3-1` 均已把旧 `/api/ai-agent/run` / `mnote-cli host` 写成历史、兼容、已覆盖或 legacy guard。
- [x] `design/10-review/04-secondary-domains-and-design-governance-review.md` 已继续指向 Hermes plugin / Rust bridge，并明确旧 `openai-agents-python` / `mnote-cli host` 只按历史/兼容/对照链处理。

建议修改范围：

- `design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`
- `design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`
- `design/03-rust-web/reference/3-rust-web-long-term-architecture-v1.md`
- `design/03-rust-web/process/3-15-runtime-fallback-retirement-checklist-v1.md`
- `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
- `design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md`
- `design/old/07-ai/process/*`

执行步骤：

- [x] 把完成证据回填到本 checklist 对应 task。
- [x] 7-4 的实现证据已满足完成定义，本文已归档到 `design/07-ai/done/` 并同步更新引用。
- [x] 保留 `7-3` 为主线设计稿；`7-4` 作为实现与验收执行清单，不覆盖 `7-3` 的架构口径。
- [x] 活跃设计稿中只允许历史、兼容、已覆盖或 legacy guard 说明提到 `mnote-cli host`。
- [x] 旧 CLI-first 文档必须继续留在 `design/old/07-ai/process/` 并标 `[recycle]`。
- [x] 更新 `design/10-review` 中旧建议，使其指向 Hermes plugin / Rust bridge。

验收标准：

- [x] `find design/07-ai -maxdepth 3 -type f | sort` 能清楚看到当前 process/done 状态。
- [x] `rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first" design --glob '*.md'` 的活跃目录命中都带有“历史/回收/已覆盖”说明。
- [x] `design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 仍保留为历史决策记录。
- [x] 没有把未完成代码能力提前标成 done。

---

## 16.1 剩余顺序执行 checklist（按 G-N 顺序）

> 这一段只收纳当前仍未完成的项，按顺序逐项勾选。每个 task 都必须在本段回填“执行命令 / 证据路径 / 结果”，不能只写口头结论。
>
> Hermes Web UI 参考目录固定为 `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/hermes-web-ui-0.5.18`。下文所有 `packages/...` 路径都相对此目录。需要对照时按列出的文件和符号打开，不整目录通读，不照搬 Vue / Naive UI / 管理台页面。

### G1：把 tool event 刷新恢复补成真实 Hermes upstream 闭环

**目标：** 证明 `mnote.page.get` 是由真实 Hermes upstream run 触发，并由 Hermes session 存储回灌；mnote 页面 AI 只消费 Hermes 事件。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| run 请求与事件字段 | `packages/client/src/api/hermes/chat.ts` | `StartRunRequest` 第 14 行；`RunEvent` 第 28 行 | 对齐 mnote proxy / Leptos 面板消费的 run event 字段 |
| session handler 注册 | `packages/client/src/api/hermes/chat.ts` | `registerSessionHandlers` 第 297 行；`resumeSession` 第 420 行；`startRunViaSocket` 第 432 行 | 对齐“按 session 订阅事件、刷新后 resume”的语义 |
| tool event 归并到消息 | `packages/client/src/stores/hermes/chat.ts` | `mapHermesMessages` 第 125 行；`case 'tool.started'` 第 910 / 1340 行；`case 'tool.completed'` 第 948 / 1378 行 | 对齐 tool started / completed 与 session detail 里的消息形态 |
| tool message 展示 | `packages/client/src/components/hermes/chat/MessageItem.vue` | `message.role === 'tool'` 第 508 行；`formatToolPayload` 第 263 行；`tool-preview` 第 543 行；`tool-details` 第 555 行 | 对齐默认折叠、摘要和详情展开，不照搬样式 |
| upstream tool event 生成 | `packages/server/src/services/hermes/chat-run-socket.ts` | `applyResponseStreamEvent` 第 1035 行；`function_call` 第 1101 / 1110 行；`tool.started` 第 1131 行；`function_call_output` 第 1145 行；`tool.completed` 第 1165 行；`flushResponseRunToDb` 第 1207 行 | 确认 tool event 来源于 upstream response stream，并最终 flush 到 Hermes DB |
| Hermes plugin 发现 | `packages/server/src/services/hermes/plugins.ts` | `PluginManager` 第 63 / 120 行；`user_dir = get_hermes_home() / "plugins"` 第 137 行；`providesTools` 第 200 行；`listHermesPlugins` 第 310 行 | 确认 mnote 工具必须进入 Hermes plugin / tool registry |

**顺序执行 checklist：**

- [x] G1.1 运行 `hermes plugins list`，确认当前 Hermes 是否已经能发现 `mnote` plugin；把输出摘要回填到本 task。
- [x] G1.2 运行 `hermes tools list --platform api_server`，确认 `mnote` toolset 或 `mnote_page_get` 是否已经可见；把输出摘要回填到本 task。
- [x] G1.3 如果 `mnote` 不可见，创建或修正用户插件目录 `/home/lix/.hermes/plugins/mnote/`，其中 `plugin.yaml` 必须声明 `name: mnote` 与 `provides_tools`，`__init__.py` 必须通过 `ctx.register_tool(..., toolset="mnote")` 注册工具。
- [x] G1.4 插件对 Hermes 暴露的函数名使用 OpenAI function-name 兼容名，例如 `mnote_page_get`；插件内部再映射到 mnote-web tool route 的 `toolName: "mnote.page.get"`。
- [x] G1.5 插件 handler 只调用 `POST http://127.0.0.1:3000/api/hermes/tools/mnote/call` 或 `MNOTE_UI_BASE_URL` 指向的同源 mnote-web route，不直接读写 Convex。
- [x] G1.6 将 `mnote` 加入 `/home/lix/.hermes/config.yaml` 的 `plugins.enabled` 后，重新运行 `hermes plugins list` 与 `hermes tools list --platform api_server`。
- [x] G1.7 触发一次真实 Hermes upstream run，请求内容使用“读取当前页面标题和页面设置”，确认模型实际选择 `mnote_page_get` / `mnote.page.get`。
- [x] G1.8 在 mnote 页面 AI 面板网络记录里确认事件来自 `/api/hermes/client/runs` 与 `/api/hermes/client/events/{run_id}` 或当前 Hermes proxy 等价入口，不是前端本地拼出的假事件。
- [x] G1.9 刷新页面后重新打开 AI 面板，确认同一 tool event 从 Hermes session detail 恢复，顺序与首次流式展示一致。
- [x] G1.10 回填证据：Hermes run id、session id、tool call id、mnote trace id、截图或 smoke 输出路径。

2026-05-14 G1 执行证据：

- [x] `python -m py_compile /home/lix/.hermes/plugins/mnote/__init__.py`：通过。
- [x] `hermes plugins list`：`mnote` 显示为 `enabled` user plugin。
- [x] `hermes tools list --platform api_server`：Plugin toolsets 中 `mnote` 显示为 enabled。
- [x] `/home/lix/.hermes/hermes-agent/venv/bin/python` 调用 `get_tool_definitions(enabled_toolsets=["mnote"])`：可见 `mnote_page_get`、`mnote_page_save`、`mnote_page_update_title`、`mnote_page_update_options`、`mnote_artifact_create_summary`、`mnote_artifact_create_ai_note`。
- [x] 发现并修复运行态差异：Hermes gateway 长进程启动早于 mnote plugin 接入，首次 `/v1/runs` 只看到 MemPalace 等旧工具；执行 `hermes gateway restart` 后真实 upstream run 可见 `mnote_page_get`。
- [x] 3000 主入口已重启为当前 `mnote-web`，并配置 `MNOTE_WEB_HERMES_UPSTREAM_URL=http://127.0.0.1:8642` 与服务端 Hermes API key；`GET /api/hermes/client/models` 经 mnote-web proxy 返回 `hermes-agent`。
- [x] 修正 `rust/crates/mnote-web/src/routes/hermes_client.rs`：Hermes run context 透传 `actorId/actorType/sessionId/traceId`，并在 `toolGuidance` 中要求读取标题/页面设置时传 `includeBody=false/includeOptions=true/includeBlocks=false`。
- [x] 验证命令：`cd rust && cargo test -p mnote-web hermes_client_run_body_carries_page_context_into_run_input -- --nocapture`：1 passed。
- [x] 验证命令：`cd rust && cargo build -p mnote-web`：通过。
- [x] 真实页面 AI 面板不 mock 验证：测试页 `TEST-HERMES-AI-realpanel-green-mp4rv3w3`，页面 AI 捕获网络请求 `POST /api/hermes/client/sessions`、`GET /api/hermes/client/sessions/{sessionId}`、`POST /api/hermes/client/runs`、`GET /api/hermes/client/events/run_4a8b09db7fbc45b8bb1bbea68b436093`，未请求 `/api/ai-agent/run`。
- [x] Hermes run：`run_4a8b09db7fbc45b8bb1bbea68b436093`，status `completed`，session `mnote_tree_1778719834312_1_page-ai-mp4rv470`，输出包含标题 `TEST-HERMES-AI-realpanel-green-mp4rv3w3` 与页面设置。
- [x] Hermes session export：`mnote_tree_1778719834312_1_page-ai-mp4rv470`，`message_count=4`，`tool_call_count=1`；assistant tool call 为 `mnote_page_get`，Hermes tool call id 为 `call_00_5B7fVip245331pk4zYyd5532`；tool message 内容 `ok=true`、`toolName=mnote.page.get`。
- [x] mnote audit：`trace_1778719842620_2b05ef8600`，mnote tool call id `tool_1778719842620_7687c1860a`，`phase=started/completed`，`effect=read`，`actorId=a4b72c17-49e3-46d3-8456-24a0a7044d64`。
- [x] 刷新恢复：同一页面刷新后重新打开 AI 面板，请求 `GET /api/hermes/client/sessions/mnote_tree_1778719834312_1_page-ai-mp4rv470`，抽屉文本恢复出 Hermes session 中的页面标题与 tool message。

**验收标准：**

- [x] 真实 Hermes upstream run 触发 `mnote.page.get`，不是直接调用 mnote-web tool smoke 假代替。
- [x] tool event 通过 Hermes run stream / session detail 回灌到页面。
- [x] 页面刷新后仍能从 Hermes session detail 恢复同一批 tool event。
- [x] 前端本地 state 只承担临时渲染，不作为 tool event 最终真相。

### H1：补 workspace ACL 负向验证与正文立即回显

**目标：** 写正文工具必须证明权限失败不泄露、成功写入后主编辑区立即可见，且 AI 面板不保存正文真相。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| 权限失败事件形态 | `packages/client/src/api/hermes/chat.ts` | `RunEvent` 第 28 行；`onToolStarted` / `onToolCompleted` 第 69-70 行；`onRunFailed` 第 73 行 | 失败也走稳定事件，不出现空白 502 |
| 失败事件持久化 | `packages/server/src/services/hermes/chat-run-socket.ts` | `emit` 第 574 / 963 行；`markCompleted` 第 978 / 1276 行；`flushResponseRunToDb` 第 1207 行 | 确认失败信息也能进入可恢复 session |
| session 只保存消息真相 | `packages/server/src/db/hermes/session-store.ts` | `HermesMessageRow` 第 35 行；`addMessage` 第 331 行；`getSessionDetail` 第 313 行 | 失败消息留在 Hermes session，不写入 mnote 正文 |
| tool failed 展示 | `packages/client/src/components/hermes/chat/MessageItem.vue` | `tool-error-badge` 第 551 行；`tool-details` 第 555 行 | 权限失败显示错误摘要，不泄露正文 |
| 写入后 UI 刷新边界 | `packages/client/src/stores/hermes/chat.ts` | `sendMessage` 第 646 行；`runHadToolActivity` 第 737 行；`cleanup` 附近 | tool 完成后刷新业务事实，不复制正文真相到 AI 面板 |

**顺序执行 checklist：**

- [x] H1.1 新增或扩展 `scripts/task-hermes-page-ai-writeback-smoke.js`：构造无 workspace 权限或无页面写权限场景，调用 `mnote.page.save`。
- [x] H1.2 断言权限失败返回稳定错误码，例如 `permission_denied` / `workspace_access_denied`，响应体不得包含页面标题、正文全文或 block 原文。
- [x] H1.3 在页面 AI 面板断言失败展示为 tool failed / permission denied，不是 502、空白或旧 provider 错误。
- [x] H1.4 正向写入时，使用测试前缀 `TEST-HERMES-AI-<timestamp>` 调用 `mnote.page.save`。
- [x] H1.5 写入完成后不刷新页面，直接断言主编辑区 island 可见新内容。
- [x] H1.6 刷新页面后再次断言新内容存在，证明业务事实已回到正式正文链。
- [x] H1.7 检查 AI 面板状态或 session detail，确认不保存完整正文副本，只保存 tool event / tool result 摘要。

2026-05-14 H1 执行证据：

- [x] 修正 `rust/crates/mnote-web/src/routes/hermes_tools.rs`：当请求头 `x-mnote-workspace-id` 与 tool payload `workspaceId` 不一致时，返回 `403 workspace_context_conflict`，不进入页面读写链。
- [x] 新增单测 `hermes_tools_reject_workspace_context_conflict_without_content_leak`：断言响应不包含测试 fixture 标题 `服务端页面` 与正文 `章节一`。
- [x] 验证命令：`cd rust && cargo test -p mnote-web hermes_tools_reject_workspace_context_conflict_without_content_leak -- --nocapture`：1 passed。
- [x] 扩展 `scripts/task-hermes-page-ai-writeback-smoke.js`：先构造 workspace 上下文冲突负向调用，断言 `403 workspace_context_conflict` 且不泄露页面标题 / 正文标记；再用页面 AI 面板 mock Hermes `tool.failed` 事件断言 UI 展示 `mnote.page.save` 与 `permission_denied`，不是 502 / 空白 / 旧 provider 错误；最后执行 dryRun、正式写入、主编辑区即时回显、幂等重试和刷新后读取。
- [x] 验证命令：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-writeback-smoke.js`：通过；最终复跑测试页 `tree_1778720381778_4`，标记 `TEST-HERMES-AI-WRITEBACK-mp4s6ubg`，写入命令 `page.body.save`，`commandId=page_body_save_req_1778720382427_413`。
- [x] smoke 在正式 `3000` 运行，写入完成后未刷新页面即等待主编辑区出现 `TEST-HERMES-AI-WRITEBACK-*` 标记；随后通过 `/api/documents/content` 读取确认刷新后仍存在。

**验收标准：**

- [x] 未授权不能写正文，且失败响应不泄露正文。
- [x] 成功写入后主编辑区即时可见。
- [x] 刷新后正文仍存在。
- [x] 页面 AI 不持有正文真相副本。

### I1：补标题与 sidebar 一致性验证

**目标：** `mnote.page.update_title` 与 `mnote.page.update_options` 只改变 mnote 页面事实；Hermes session 标题、模型状态和页面标题不能混成一份真相。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| session title 只是会话标题 | `packages/server/src/db/hermes/session-store.ts` | `HermesSessionRow` 第 9 行；`renameSession` 第 202 行 | 区分 Hermes 会话标题与 mnote 页面标题 |
| session detail 字段 | `packages/server/src/db/hermes/session-store.ts` | `HermesSessionDetailRow` 第 56 行；`getSessionDetail` 第 313 行 | 刷新恢复 AI 会话，不恢复页面标题草稿 |
| 面板标题展示 | `packages/client/src/components/hermes/chat/ChatPanel.vue` | `activeSessionTitle` 第 193 行；`headerTitle` 第 197 行；`SessionListItem` 第 598 / 636 行；`MessageList` 第 790 行；`ChatInput` 第 791 行 | AI 面板只展示 session 语义，不维护页面标题草稿 |
| session 列表标题 | `packages/client/src/components/hermes/chat/SessionListItem.vue` | `session-item-title` 第 94 行；`session.title` 第 96 行；`session-item-model` 第 100 行 | 不把 sidebar 页面标题同步需求写进 Hermes session list |
| model 展示边界 | `packages/client/src/components/layout/ModelSelector.vue` | `selectedDisplayName` 第 16 行；`handleSelect` 第 64 行；`model-name` 第 105 行；`model-item` 第 142 行 | model 真相不回写 mnote page aggregate |

**顺序执行 checklist：**

- [x] I1.1 扩展 `scripts/task-hermes-page-ai-title-options-smoke.js`，修改标题为 `TEST-HERMES-AI-<timestamp>`。
- [x] I1.2 断言页头标题、breadcrumb/current title、sidebar 树节点标题三处立即一致。
- [x] I1.3 刷新页面后再次断言三处标题一致，且值来自页面真源。
- [x] I1.4 断言 AI 面板 session 标题没有被当成 mnote 页面标题真相。
- [x] I1.5 调用 `mnote.page.update_options` 修改 `smallText` 或 `wideLayout`，确认只接受 `runtimeSupport == "wired"` 字段。
- [x] I1.6 对 `planned` / `ui_only` 字段执行 dryRun 或正式调用，确认返回明确警告或错误，不产生页面事实写入。

2026-05-14 I1 执行证据：

- [x] 修正 `rust/crates/mnote-web/src/hermes_tools/page.rs`：`mnote.page.update_options` 对未接线字段返回 `ignoredOptions` 与 `warnings`，并只把 wired 字段放入 `page.layout.updateOptions` payload。
- [x] 扩展单测 `hermes_tools_update_options_dry_run_filters_unwired_fields`：断言 `pageFont` 不进入 `diff.payload.options`，并返回 `ignoredOptions[0]="pageFont"` 与 `warnings[0].code="page_option_not_wired"`。
- [x] 验证命令：`cd rust && cargo test -p mnote-web hermes_tools_update_options_dry_run_filters_unwired_fields -- --nocapture`：1 passed。
- [x] 验证命令：`cd rust && cargo build -p mnote-web`：通过。
- [x] 验证命令：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js`：通过；测试页 `tree_1778720870666_1`，标题 `TEST-HERMES-AI-title-updated-mp4shbjq`。
- [x] smoke 已断言页头标题、breadcrumb/current title、sidebar 树节点标题一致；`data-page-wide-layout=true` 与 `data-page-small-text=true` 生效。
- [x] smoke 已打开页面 AI 面板，确认 `data-mnote-page-ai-session-owner=hermes`，localStorage 仅保存 `{"activeSessionId":"mnote_tree_1778720870666_1_page-ai-mp4shbwk"}`，不保存页面标题。

**验收标准：**

- [x] 标题修改后页头、breadcrumb、sidebar、刷新后标题一致。
- [x] 页面设置修改只允许 wired 字段。
- [x] AI 面板没有独立标题状态。

### J1：补 artifact reference edge 与 projection-only 验收

**目标：** artifact 工具经 Hermes tool call 与 Rust kernel 创建业务事实，`AI Artifacts` 只是 projection 分组，不是真实 kernel node。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| artifact 工具作为 plugin/tool 暴露 | `packages/server/src/services/hermes/plugins.ts` | `providesTools` 第 200 行；`providesHooks` 第 201 行；`requiresEnv` 第 202 行 | artifact 能力挂到 Hermes plugin，不做 mnote-web 私有按钮直写 |
| artifact 结果仍是 tool event | `packages/client/src/api/hermes/chat.ts` | `RunEvent` 第 28 行；`onToolCompleted` 第 70 行 | summary / ai_note 结果作为 tool event 展示 |
| tool result 展示 | `packages/client/src/components/hermes/chat/MessageItem.vue` | `toolPreview` 第 543 行；`toolResultPayload` 第 332 行；`tool-details` 第 555 行 | artifact 结果只展示摘要和详情，不写入正文 |
| 历史 tool message 恢复 | `packages/client/src/stores/hermes/chat.ts` | `mapHermesMessages` 第 125 行；`case 'tool.completed'` 第 948 / 1378 行 | 刷新后 artifact tool event 仍从 session 恢复 |
| session DB tool 字段 | `packages/server/src/db/hermes/session-store.ts` | `tool_call_id` 第 40 行；`tool_calls` 第 41 行；`tool_name` 第 42 行；`addMessage` 第 331 行 | tool call id 与 artifact audit 能串联 |

**顺序执行 checklist：**

- [x] J1.1 扩展 `scripts/task-hermes-page-ai-artifact-smoke.js`，创建或更新 summary，记录 `artifactDocumentId`。
- [x] J1.2 通过 kernel query 或稳定 projection route 查询 summary 与当前页面之间的 reference edge。
- [x] J1.3 再创建两次 ai_note，断言每次得到独立 `artifactDocumentId`。
- [x] J1.4 查询每个 ai_note 与当前页面之间的 reference edge，确认 `from/to/kind` 可追踪。
- [x] J1.5 查询 `AI Artifacts` 分组来源，确认它是 projection-only 分组，不是真实 kernel node。
- [x] J1.6 回查 artifact audit，确认包含 `sessionId/runId/toolCallId/traceId`。

2026-05-14 J1 执行证据：

- [x] `cargo test -p bridge-runtime ai_artifact -- --nocapture`：2 passed。
- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js`：通过；`referenceEdgeCount=6`，`meta.aiArtifacts.projectionOnly=true`，`kernelNodeId=null`，`auditEventCount=6`。

**验收标准：**

- [x] reference edge 可通过 kernel query 或 projection 查询。
- [x] `AI Artifacts` 只是 projection-only 分组。
- [x] summary 与 ai_note 行为符合既定幂等 / 新建规则。
- [x] artifact 写入 audit 能串到 Hermes tool call。

### K1：补 legacy 调用方清点与退场文档

**目标：** 旧 `/api/ai-agent/run` 只保留为 legacy guard / 历史说明，不再被活跃设计或页面 AI 主链描述为长期入口。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| 新 run 入口 | `packages/client/src/api/hermes/chat.ts` | `startRunViaSocket` 第 432 行 | 对照新页面 AI 主链，不回到旧 `/api/ai-agent/run` |
| run server 注册 | `packages/server/src/routes/hermes/chat-run.ts` | `setChatRunServer` 第 5 行；`getChatRunServer` 第 9 行 | 确认 Hermes run server 是真实入口 |
| upstream run 生命周期 | `packages/server/src/services/hermes/chat-run-socket.ts` | `handleRun` 第 488 行；`markCompleted` 第 1276 行 | 长期主链是 Hermes upstream run |
| plugin 发现 | `packages/server/src/services/hermes/plugins.ts` | `listHermesPlugins` 第 310 行 | 旧入口退场后，mnote 能力从 Hermes plugin/tool 面进入 |

**顺序执行 checklist：**

- [x] K1.1 运行 `rg -n "/api/ai-agent/run|provider=hermes|mnote-cli host|CLI-first" design rust wolai-frontend scripts --glob '*.md' --glob '*.rs' --glob '*.ts' --glob '*.tsx' --glob '*.js'`。
- [x] K1.2 将命中逐项归类为：`历史证据`、`legacy guard`、`仍需迁移`、`误导性活跃口径`。
- [x] K1.3 对 `仍需迁移` 的代码调用方补迁移或补退场 guard。
- [x] K1.4 对 `误导性活跃口径` 的设计稿改写为“历史/兼容/已覆盖”，必要时移入 `design/old/` 并标 `[recycle]`。
- [x] K1.5 更新旧 smoke：不再期待 `/api/ai-agent/run -> mnote-cli` 成功，只验证 legacy guard 返回稳定退场码。
- [x] K1.6 在本 checklist 回填 rg 输出摘要和修改文件清单。

2026-05-14 K1 执行证据：

- [x] rg 命中已归类：`design/old/**` 与 `design/07-ai/done/7-1**` 为历史证据；`scripts/task-hermes-page-ai-retirement-guard.js` 与 `rust/crates/mnote-web/src/routes/compat.rs` 为 legacy guard；旧 E27/phase7/page-ai smoke 已默认退役；`wolai-frontend` 中 Mindmap / OnlyOffice / generic AI 面板调用点归为非当前页面 AI 主链的 legacy domain 调用点，后续按各自 domain 迁移。
- [x] 修改文件：`rust/crates/mnote-web/src/routes/compat.rs`、`scripts/task-hermes-page-ai-retirement-guard.js`、历史退役 smoke 当前本机归档于 gitignored `recycle/scripts/retired-ai-agent-run-smokes/`、`design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`、`design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md`、`design/10-review/04-secondary-domains-and-design-governance-review.md`。
- [x] 旧 smoke 默认退役验证：上述 6 个历史 smoke 均返回 `{ ok: true, retired: true }`。

**验收标准：**

- [x] 活跃设计稿不再把 `/api/ai-agent/run` 描述为页面 AI 长期入口。
- [x] legacy 调用方清单为空，或每一项都有明确退场说明。
- [x] 旧入口不会静默 fallback 到 Hermes、Codex 或旧 orchestrator。

### L1：把审计从进程内缓存收口到持久化可追踪链

**目标：** 每次 Hermes 调用 mnote 工具都能从页面 AI 请求串到 Hermes run、mnote tool call、Rust command 和最终业务结果。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| 前端事件字段 | `packages/client/src/api/hermes/chat.ts` | `RunEvent` 第 28 行，重点看 `run_id`、`session_id`、`tool`、`name` | 前端事件字段要能和审计字段串联 |
| run / tool / session 追踪 | `packages/server/src/services/hermes/chat-run-socket.ts` | `emit` 第 574 / 963 行；`applyResponseStreamEvent` 第 1035 行；`flushResponseRunToDb` 第 1207 行；`markCompleted` 第 1276 行 | 对齐 run、tool、session 三段追踪模型 |
| tool call 持久字段 | `packages/server/src/db/hermes/session-store.ts` | `tool_call_id` 第 40 行；`tool_calls` 第 41 行；`tool_name` 第 42 行；`addMessage` 第 331 行 | mnote audit 至少能关联 Hermes tool call id |
| usage 不进页面事实 | `packages/server/src/db/hermes/usage-store.ts` | `recordUsage` 第 16 行；`getUsage` 第 53 行；`getUsageBatch` 第 73 行；`deleteUsage` 第 118 行 | usage/model 是 Hermes 真相，不写入 mnote page aggregate |

**顺序执行 checklist：**

- [x] L1.1 定义持久化审计落点：复用现有 audit/event log，或新增最小 `mnote_hermes_tool_audit` 存储；不得只依赖进程内缓存。
- [x] L1.2 审计字段固定包含 `traceId/sessionId/runId/toolCallId/documentId/workspaceId/actorId/toolName/effect/commandId/errorCode`。
- [x] L1.3 在 tool call start / success / failure 三个阶段写入同一条可查询链。
- [x] L1.4 更新 `scripts/task-hermes-page-ai-audit-smoke.js`，重启进程或绕过进程内缓存后仍能按 `traceId` 回查审计。
- [x] L1.5 权限失败场景必须断言审计里没有完整正文、无权限页面标题或 block 原文。
- [x] L1.6 写工具成功场景必须断言审计能追踪到最终 Rust command id。

2026-05-14 L1 执行证据：

- [x] `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js`：通过，`persistedOnly=true` 查询确认持久化审计可按 traceId 回查。
- [x] 权限失败审计：`deniedPersistedPhases=["started","failed"]`，smoke 已断言持久化 audit 不含正文 marker 与页面标题。

**验收标准：**

- [x] 每个 tool call 都能追踪到 session、run、toolCall 和最终业务结果。
- [x] 失败不泄露内容。
- [x] 审计不是只存在于进程内缓存。

### M1：把正式 `3000` 的 E2E smoke 跑成最终验收矩阵

**目标：** 临时 `3019` 证据不能作为最终完成；必须在正式 `3000` + 真实 SQLite control-plane Auth / session 上复跑全矩阵。历史记录中的 Convex Auth 只作为当时验收背景。

**必须参考 Hermes Web UI 的位置：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | mnote 采用方式 |
| --- | --- | --- | --- |
| run / resume / abort 客户端入口 | `packages/client/src/api/hermes/chat.ts` | `startRunViaSocket` 第 432 行；`resumeSession` 第 420 行；`registerSessionHandlers` 第 297 行 | 作为 E2E smoke 的网络断言依据 |
| session detail | `packages/client/src/api/hermes/sessions.ts` | `SessionSummary` 第 3 行；`HermesMessage` 第 36 行；`fetchSessions` 第 50 行；`fetchSession` 第 81 行 | 刷新恢复 smoke 必须断言 session detail |
| run 生命周期 | `packages/server/src/services/hermes/chat-run-socket.ts` | `resumeSession` 第 427 行；`handleRun` 第 488 行；`markCompleted` 第 1276 行 | 正式 `3000` 上断言 run 生命周期完整 |
| 面板组件边界 | `packages/client/src/components/hermes/chat/ChatPanel.vue` | `SessionListItem` import 第 22 行、使用第 598 / 636 行；`MessageList` 第 790 行；`ChatInput` 第 791 行 | 只对齐页面 AI 抽屉需要的子集 |

**顺序执行 checklist：**

- [x] M1.1 确认主入口 `http://127.0.0.1:3000` 运行的是包含本轮改动的 `mnote-web`，不是旧进程。
- [x] M1.2 使用默认 SQLite control-plane 测试账号 `mnote.e2e@example.com` 登录，不使用 `MNOTE_DEV_AUTH=1` 伪登录作为正式验收；旧 Convex Auth 仅作 compat 回归。
- [x] M1.3 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js`。
- [x] M1.4 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-tool-smoke.js`。
- [x] M1.5 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-writeback-smoke.js`。
- [x] M1.6 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-title-options-smoke.js`。
- [x] M1.7 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-artifact-smoke.js`。
- [x] M1.8 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-retirement-guard.js`。
- [x] M1.9 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-mobile-smoke.js`。
- [x] M1.10 运行 `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-audit-smoke.js`。
- [x] M1.11 确认 smoke 只操作本轮新建测试数据，统一前缀 `TEST-HERMES-AI-<timestamp>`。
- [x] M1.12 任一 smoke 失败时，把失败写入 `bugs/07-ai/process/` 或真实 owner 分类，不在 checklist 里标 GREEN。

**验收标准：**

- [x] 所有 smoke 在正式 `3000` 通过。
- [x] 可以定位每次 smoke 生成的页面、artifact、edge 和 audit。
- [x] 任一 smoke 失败都会落到 `bugs/`，不会在 checklist 中假装通过。

### N1：把活跃设计口径和 old 目录治理收口

**目标：** 设计目录与真实主线一致：页面 AI 是 Hermes 面板，mnote 通过 Hermes skill/plugin 被调用，旧 CLI-first 口径只保留为历史。

**必须参考的本仓设计文件：**

| 参考目的 | 具体文件 | 具体位置 / 搜索点 | 处理方式 |
| --- | --- | --- | --- |
| Page Aggregate 口径 | `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md` | 搜索 `/api/ai-agent/run`、`mnote-cli host`、`页面 AI` | 改成历史残留 / 已覆盖 / 待迁移证据，不写成长期主线 |
| Wolai-aline 过渡基线 | `design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md` | 搜索 `E27`、`mnote-cli`、`页面 AI` | 保留为对标基线时必须标明过渡状态 |
| 二级域 review 建议 | `design/10-review/04-secondary-domains-and-design-governance-review.md` | 搜索 `Hermes`、`plugin`、`mnote-cli`、`CLI-first` | 指向 Hermes plugin / Rust bridge 的当前口径 |
| 07-ai 历史稿 | `design/old/07-ai/process/` | 搜索 `CLI-first`、`mnote-cli` | 继续标 `[recycle]`，不迁回活跃 process |

**顺序执行 checklist：**

- [x] N1.1 运行 `rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'`。
- [x] N1.2 把命中分为 `design/old` 历史命中、活跃历史说明、活跃误导口径三类。
- [x] N1.3 修改 `5-6`、`5-9`、`10-review` 中仍残留的旧 CLI-first 说法，使其明确为历史/兼容/已覆盖。
- [x] N1.4 确认 `design/old/07-ai/process/` 中历史稿继续标 `[recycle]`。
- [x] N1.5 7-4 全部验收标准已满足，本文已按 design 归档规则移动到 `design/07-ai/done/`；新的活跃执行清单改由 `7-7` 承接。
- [x] N1.6 回填最终 rg 输出摘要和 design 文件迁移清单。

2026-05-14 N1 执行证据：

- [x] `rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'` 已跑完，活跃命中已逐项归类。
- [x] 活跃命中主要落在 `design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`、`design/05-editor-mainline/reference/5-9-wolai-aline-continuous-checklist-v1.md`、`design/10-review/04-secondary-domains-and-design-governance-review.md`、`design/10-review/06-execution-checklist-and-acceptance.md`、`design/01-tree-first-graph-kernel/reference/1-1-tree-first-graph-kernel-checklist-v2.md`、`design/03-rust-web/reference/3-1-rust-web-long-term-checklist-v2.md`、`design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`、`design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md`、`design/07-ai/done/7-5-hermes-client-proxy-contract-v1.md`、`design/07-ai/done/7-6-mnote-hermes-plugin-tool-contract-v1.md`。
- [x] `design/old/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 与同目录旧稿继续保留 `[recycle]`，只作为历史证据。
- [x] 本轮对 `5-6`、`5-9`、`10-review/04`、`10-review/06`、`1-1`、`3-1` 的旧口径改写已完成；活跃文档现已统一为 Hermes 页面内客户端 + mnote Hermes plugin/tool 口径。
- [x] 本文件仍保留在 `process/`，原因是它是执行清单而不是代码实现文件；若后续需要归档，可按 `N1.5` 的规则移动并同步更新引用。

**验收标准：**

- [x] 活跃目录的旧 CLI-first 命中都带有历史/回收/已覆盖说明。
- [x] `design/old/07-ai/process/` 保持历史记录定位。
- [x] 未完成能力不会被提前标 done。

---

## 17. 推荐执行顺序总表

| 顺序 | Task | 目标 | 退出门槛 |
| --- | --- | --- | --- |
| 1 | A | 固定旧链与 502 基线 | 有可复跑证据 |
| 2 | B | 冻结 Hermes client proxy 合同 | route 输入输出示例齐全 |
| 3 | C | 实现 Hermes client proxy 只读链 | session/run 可代理 |
| 4 | D | 冻结 mnote plugin tool 合同 | 第一批 tool schema 齐全 |
| 5 | E | 实现 manifest + `mnote.page.get` | Hermes 可读当前页 |
| 6 | F | 实现 Leptos Hermes 面板 | 页面 AI 不再请求旧 run route |
| 7 | G | 展示 tool event | tool started/completed 可刷新恢复 |
| 8 | H | 正文写入工具 | `page.body.save` 闭环 |
| 9 | I | 标题与页面设置工具 | 标题/设置走 Page Aggregate |
| 10 | J | artifact 工具 | summary / ai_note / reference edge 闭环 |
| 11 | K | 退役旧主链 | 旧 route 不再承载页面 AI 主路径 |
| 12 | L | 审计与可观测性 | tool call 到 Rust command 可追踪 |
| 13 | M | 端到端验收矩阵 | 全 smoke 通过 |
| 14 | N | 文档治理回填 | design 口径无旧主线残留 |

---

## 18. 最终完成定义

只有同时满足以下条件，才能宣布本 checklist 完成：

- [x] Hermes session 是页面 AI 会话真相。
- [x] mnote 只保存业务事实和审计，不保存聊天真相。
- [x] 页面 AI 面板是 Leptos Hermes client，不是 `mnote-cli` 面板。
- [x] mnote Hermes plugin 至少覆盖读取当前页、写正文、改标题/设置、创建 summary、创建 ai_note。
- [x] 所有写入经 Rust runtime / kernel。
- [x] 旧 `/api/ai-agent/run` 不再是页面 AI 主入口。
- [x] E2E smoke 覆盖只读、写入、artifact、刷新恢复、旧链退役；正式 `http://127.0.0.1:3000` 已复跑 8 个 smoke，见 Task M。
- [x] 活跃设计文档和执行清单一致；旧 CLI-first / `/api/ai-agent/run` 命中均已标为历史、兼容、已覆盖或 legacy guard。

### 18.1 最终完成审计记录

2026-05-14 最终复核按“完成定义 -> 真实证据”逐项检查，不只依赖本文勾选状态。

- [x] 运行态入口存在：`ss -ltnp | rg ':3000\b|:8642\b'` 确认 `mnote-web` 监听 `0.0.0.0:3000`，Hermes API server 监听 `127.0.0.1:8642`。
- [x] Rust tool / client / legacy guard 测试通过：
  - `cargo test -p bridge-runtime ai_artifact -- --nocapture`：2 passed。
  - `cargo test -p mnote-web hermes_client -- --nocapture`：4 passed。
  - `cargo test -p mnote-web hermes_tools_ -- --nocapture`：9 passed。
  - `cargo test -p mnote-web ai_agent_run -- --nocapture`：1 passed。
  - `cargo test -p mnote-web explicit_ -- --nocapture`：2 passed。
  - `cargo build -p mnote-web`：通过。
- [x] Hermes plugin/toolset 可见：
  - `hermes plugins list`：`mnote` 为 enabled user plugin。
  - `hermes tools list --platform api_server`：Plugin toolsets 中 `mnote` 为 enabled。
  - `/home/lix/.hermes/plugins/mnote/plugin.yaml` 声明 `mnote_page_get`、`mnote_page_save`、`mnote_page_update_title`、`mnote_page_update_options`、`mnote_artifact_create_summary`、`mnote_artifact_create_ai_note`。
- [x] 正式 `3000` smoke 全矩阵通过：
  - `task-hermes-page-ai-smoke.js`：`tree_1778724401995_17`，session `mnote_smoke_mp4ul0c2`，run `run_smoke_mp4ul0c2`，`sessionDetailHits=2`。
  - `task-hermes-page-ai-tool-smoke.js`：`tree_1778724413742_19`，`mnote.page.get` 返回标题 `TEST-HERMES-AI-tool-mp4ul9ei`。
  - `task-hermes-page-ai-writeback-smoke.js`：`tree_1778724445965_21`，`page.body.save`，command `page_body_save_req_1778724446747_1371`。
  - `task-hermes-page-ai-title-options-smoke.js`：`tree_1778724480369_23`，`page.head.updateTitle` 与 `page.layout.updateOptions` 通过，`pageFont` 返回 `page_option_not_wired`。
  - `task-hermes-page-ai-artifact-smoke.js`：`tree_1778724511207_25`，summary / ai_note 都走 `tree.node.create`，`referenceEdgeCount=6`，`projectionOnly=true`。
  - `task-hermes-page-ai-retirement-guard.js`：旧入口返回 `410 legacy_ai_agent_run_retired`。
  - `task-hermes-page-ai-mobile-smoke.js`：`390px` viewport 下 drawer / panel 未横向溢出。
  - `task-hermes-page-ai-audit-smoke.js`：`tree_1778724538669_29`，写命令 `page_body_save_req_1778724538893_1707`，持久化 audit 覆盖 `started/completed` 与权限失败 `started/failed`。
- [x] 真实 Hermes upstream session 补充验证：页面 AI 不拦截 Hermes 请求时触发真实 run，`hermes sessions export --session-id mnote_tree_1778724800891_37_page-ai-mp4utko0 -` 显示 `message_count=4`、`tool_call_count=1`、`api_call_count=2`、`has_mnote_page_get=true`。
- [x] 文档治理检查通过：
  - `rg -n "mnote-cli.*唯一|唯一长期 agent|CLI-first|/api/ai-agent/run|provider=hermes" design --glob '*.md'` 的活跃命中均为历史、兼容、已覆盖、禁止项或 legacy guard 说明。
  - `git diff --check` 覆盖本轮已跟踪设计稿，无空白错误。
  - `rg -n "[ \t]+$"` 覆盖本轮设计稿，无尾随空白。
