# 5-9 [reference] Wolai-aline 连续执行 checklist v1

> 更新时间：2026-05-18
>
> 当前状态：`reference`。本文保留 Wolai-aline 连续项基线；新对标任务必须按 `wolai-aline` skill 和 `design/08-wolai-aline-test-flow/reference/wolai-aline-test-flow-v1.md` 另拆具体 checklist。
>
> 2026-05-18 口径补充：
> - 本 checklist 的 Wolai 体验对标仍有效，但数据真相口径跟随 local-first workspace：本地 `.md` 是默认正文真相，Convex-backed 路径只作为兼容 / cloud source。
> - 历史条目中“写回 Convex-backed 持久化底座”的表述只代表当时 smoke 的在线路径，不再作为新增编辑能力默认目标。
>
> 本清单拆自 `5-7-wolai-page-tree-main-editor-experience-restoration-v1.md`。它不是新的测试方案；执行口径统一服从 `/home/lix/.codex/skills/wolai-aline` 与 `/mnt/Data1T/mnote/design/08-wolai-aline-test-flow/reference/wolai-aline-test-flow-v1.md`。

## 1. 使用方式

每次只领取一个最小可对标任务，按下面固定闭环推进：

1. 用一句话定义行为，例如“侧栏搜索入口打开全局搜索 modal 且 URL 不变”。
2. 派 subagent 对 Wolai Hermes 取基线，必要时进入 Hermes editable-test mode。
3. 主线程查看 Wolai 截图，填写差异矩阵，不接受只有文字的结论。
4. 写或更新本地 `scripts/task*-smoke.js`，先让当前 `3000` 暴露差异。
5. 小范围实现，不新增第二套页面树、标题、正文或排序真相。
6. 运行本地 smoke 和改动范围内单测。
7. 再派 subagent 同链路复测 Wolai 与 `3000`。
8. 主线程复核最终截图；若肉眼仍有差异，先补 smoke 或 checklist 断言，再继续修。
9. 更新本清单状态和截图路径。

状态标记：`TODO` 未开始，`BASELINE` 已取 Wolai 基线，`RED` 已有本地失败 smoke，`GREEN` 本地实现和 smoke 通过，`PARITY` subagent 复测与主线程截图复核通过，`BLOCKED` 有阻塞。


## 2. 当前基线证据

2026-04-30 已由 subagent 使用 Playwright 同时操作 Wolai Hermes 与本地 `3000`，主线程已复核关键截图。后续任务可沿用这些基线，但每个具体小任务仍需重新截同动作链证据。

| 项 | Wolai 证据 | 本地证据 | 当前结论 |
| --- | --- | --- | --- |
| 首屏 | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/doc-baseline-mini/wolai-initial.png` | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/doc-baseline-mini/local-initial.png` | 历史基线显示本地首屏曾停留在聚合/预览壳；该差异已由 `task130` 收口，当前保留为基线证据 |
| 搜索 modal | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/baseline-20260430/wolai-03-search-modal-controls-filled.png` | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/baseline-20260430/local-03-search-modal-controls-filled.png` | 容器接近；结果态、数据、入口矩阵仍需拆开验；switch 状态必须截图 + `aria-checked` 双证据 |
| 块 hover | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/baseline-20260430/wolai-08-block-hover-insert-entry.png` | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/baseline-20260430/local-14-block-hover-insert-entry.png` | 本地已有 `+` 与手柄入口，但位置、密度、页面状态不同，不可判定已对齐 |
| 编辑清理 | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/baseline-20260430/wolai-14-title-suffix-after.png` | `/mnt/Data1T/mnote/tmp/wolai-editor-parity/baseline-20260430/local-16-editor-after-undo-cleanup.png` | Wolai 标题和正文都可编辑，editable-test 前必须先确认焦点 block 类型 |

当前仍需优先拆解的差异：

1. 搜索入口矩阵：Wolai 左侧搜索可打开，`Ctrl+K` 本轮未稳定；本地侧栏入口和快捷键要继续按 smoke 验证。
2. 搜索结果数据：Wolai 对 `Hermes` 有真实结果，本地依赖当前工作区示例数据；后续需要固定 fixture 或种子。
3. 编辑器测试焦点：写入前必须确认当前焦点在正文测试块，不在标题或 breadcrumb 渲染副本。


### 2.1 task129 Phase A 执行记录

2026-04-30 已新增并执行 `scripts/task129-wolai-aline-baseline-smoke.js`，用于固化 Phase A 的只读基线取证入口。该脚本不编辑 Wolai，只做双端首屏取证、DOM 摘要和差异矩阵输出。

主线程验证：

- 命令：`WOLAI_ALINE_RUN_ID=main-20260430-122309 node scripts/task129-wolai-aline-baseline-smoke.js`
- 结果：通过，`ok: true`，确认 `simultaneous: true`
- 矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/main-20260430-122309/comparison-matrix.md`
- Wolai 截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/main-20260430-122309/wolai-1392x1213-first-screen.png`
- 本地截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/main-20260430-122309/local-1392x1213-first-screen.png`

主线程多视口验证：

- 命令：`WOLAI_ALINE_RUN_ID=main-viewports-20260430-122418 WOLAI_ALINE_VIEWPORTS=1392x1213,1440x900,390x844 node scripts/task129-wolai-aline-baseline-smoke.js`
- 结果：通过，生成 `1392x1213`、`1440x900`、`390x844` 三组 Wolai / 本地截图
- 矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/main-viewports-20260430-122418/comparison-matrix.md`

subagent 复测：

- 命令：`WOLAI_ALINE_RUN_ID=subagent-20260430-122359 node scripts/task129-wolai-aline-baseline-smoke.js`
- 结果：通过，`ok: true`，确认 `simultaneous: true`，本次不需要 `xvfb-run`
- 矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/subagent-20260430-122359/comparison-matrix.md`
- Wolai 截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/subagent-20260430-122359/wolai-1392x1213-first-screen.png`
- 本地截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/subagent-20260430-122359/local-1392x1213-first-screen.png`

主线程截图复核结论：

- Wolai Hermes 为 owner 登录态，直接显示正文页和 `全网公开` 状态。
- `task129` 只证明取证工具链可用，不证明 UI 已对齐；其中暴露出的 `D9 普通文档首屏入口语义` 已在后续 `task130` 中收口。

### 2.2 task130 D9 执行记录

2026-04-30 已新增并执行 `scripts/task130-wolai-aline-root-document-entry-smoke.js`，用于固化 `D9 普通文档首屏入口语义`。该脚本启动临时 `mnote-web` 端口验证新代码路径，不修改现有 `3000` 进程。

RED：

- 初次运行失败：`AssertionError: 根页不应停在需要点击“打开当前页面”的聚合入口`
- 失败原因：Rust Web root route 在有 active page 时只渲染 workspace entry 和 `打开当前页面` 链接，没有内嵌 Page Aggregate、editor bootstrap 和 `leptos-tiptap` island。

GREEN：

- 命令：`node scripts/task130-wolai-aline-root-document-entry-smoke.js`
- 结果：通过
- 本地截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task130-root-document-entry/local-root-document-entry.png`
- smoke 断言：根页不再出现 `打开当前页面`；存在 `document-shell[data-editor-host="leptos_tiptap_island"]`；存在 `__MNOTE_PAGE_AGGREGATE__`、`__MNOTE_EDITOR_BOOTSTRAP__`；存在 `.ProseMirror[contenteditable="true"]`。

实现摘要：

- root route 在 active page 可加载 Page Aggregate 时，直接复用 `DocumentPage`、Page Aggregate snapshot、editor bootstrap、title controller 和 island adapter。
- 若 active page 不能加载 Page Aggregate，回退旧 workspace entry，避免 recent cookie 指向失效页面时 root 直接 400。
- 现有 `3000` 进程仍是旧实例；需要重启 `mnote-web` 后，`3000` 才会体现该改动。

验证：

- `cargo fmt -p mnote-web --check`
- `cargo check -p mnote-web`
- `cargo test -p mnote-web root_entry -- --nocapture`
- `node scripts/task130-wolai-aline-root-document-entry-smoke.js`


最终对标复核：

- subagent 命令：`node scripts/task130-wolai-aline-root-document-entry-smoke.js`
- 结果：通过
- Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task129-baseline/main-20260430-122309/wolai-1392x1213-first-screen.png`
- 本地截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task130-root-document-entry/local-root-document-entry.png`
- 结论：D9 目标行为一致；剩余侧栏数据、图标细节、具体字号属于后续 Sidebar / visual token checklist。
## 3. 通用证据矩阵

每个 checklist 项都必须保留以下字段：

| 字段 | 要求 |
| --- | --- |
| Wolai 截图 | 绝对路径，保存在 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/<task>/` |
| 本地截图 | 同视口、同动作链截图 |
| 入口 | 按钮、快捷键、菜单或 hover 区域 |
| 关闭路径 | Esc、再次快捷键、遮罩、关闭按钮、入口 toggle |
| URL | 操作前后是否变化 |
| 控件类型 | switch、button、dropdown、menu、input、panel、modal |
| 控件状态 | checked、selected、disabled、focused、hover、active |
| 视觉形态 | 尺寸、位置、间距、阴影、颜色、图标、遮罩 |
| DOM/ARIA | role、aria、data-testid、可聚焦性 |
| smoke | 对应 `scripts/task*-smoke.js` 或测试文件 |
| 剩余差异 | 不允许空泛写“基本一致” |

## 4. Phase A：基线和全局 token


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| A1 | GREEN | 固定基线视口与截图目录 | `task129` 已支持 `WOLAI_ALINE_VIEWPORTS`；主线程已生成 `1392x1213`、`1440x900`、`390x844` 三组截图；subagent 已复测默认视口 |
| A2 | PARITY | Wolai owner 首屏基线 | `task129` 主线程与 subagent 均确认 Wolai owner 登录态，截图见 2.1 执行记录 |
| A3 | PARITY | 本地 `3000` 首屏基线 | `task129` 主线程与 subagent 均确认本地 3000 可打开，截图见 2.1 执行记录 |
| A4 | TODO | 字体栈与基础 token | smoke 或 DOM 断言全局字体、标题字号、正文行高、sidebar 行高；截图确认中文字宽接近 Wolai |
| A5 | PARITY | 截图差异表模板落地 | `task129` 自动输出 `comparison-matrix.md`，主线程已复核截图，subagent 已独立复测 |
| A6 | PARITY | 同时操作工具链固化 | `task129` 固定 `Playwright + Chrome persistent profile`；主线程与 subagent 均确认可同时操作两个目标，本次 subagent 不需要 `xvfb-run` |

## 5. Phase B：Sidebar / 页面树


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| B1 | PARITY | 侧栏宽度与背景 | `task131` 覆盖宽 `248px`、背景 `rgb(245,245,245)`、无右侧 inset、topbar.x=sidebar.right；subagent post-fix2 复核通过 |
| B2 | PARITY | workspace header | `task132` 覆盖 header `40px`、avatar `24x24`、字号 `16px`；Wolai DOM 锚点弱，主线程与 subagent 以截图复核通过 |
| B3 | PARITY | 快捷入口行 | `task132` 覆盖 6 个快捷入口、30px 容器、约 10.4px 间距；截图复核通过 |
| B4 | PARITY | 页面树行密度 | `task132` 覆盖行高 `32px`、字号 `16px`、无额外行 margin；截图复核通过 |
| B5 | PARITY | 当前页选中态 | `task132` 覆盖淡红底 `rgba(255,71,71,.1)`、红字、`aria-current=page` / `aria-selected=true`；截图复核通过 |
| B6 | PARITY | 层级缩进 | `task132` 使用父子页面 fixture 覆盖行 x 不变、一级子行内部缩进 `20px`；服务端和运行时均补齐 depth 语义 |
| B7 | PARITY | 页面树 hover action | `task132` 覆盖 hover 仅出现“更多操作 / 新建子页面”两个 24px action；subagent post-fix2 复核通过 |
| B8 | PARITY | 页面树上下文菜单 | `task132` 覆盖宽约 `220px`、9 项命令、分组间距和 `Alt+` / `Del` 提示；高风险删除仍经确认 |
| B9 | PARITY | 底部垃圾桶/模板中心 | `task132` 覆盖 footer `44px`、无顶部分隔线、垃圾箱/模板中心固定底部；截图复核通过 |
| B10 | PARITY | 文件树创新入口 | 保留 Explorer tab；`task132` 复核主路径仍是“我的页面”，footer 与行高体系不被破坏；与 Wolai 无 Explorer 的差异按本地创新入口保留 |
| B11 | PARITY | 页面树图标与展开箭头 | `task133` 覆盖 Wolai 每行不同私有 glyph、本地无真实 icon 数据时不得用统一房子图标，也不保留空 icon slot；展开箭头使用 20x20 SVG chevron |

### 5.1 task131 / task132 / task133 Phase B 执行记录

2026-04-30 已完成 Phase B：Sidebar / 页面树。执行口径按 `wolai-aline` skill：先由 subagent 取 Wolai 基线，主线程查看截图并写 RED smoke，再最小实现，最后本地与 subagent 复测。用户复核指出 `task132` 漏掉页面树图标/箭头差异后，补充 `task133` 将该类肉眼差异固化为 smoke。

RED / GREEN：

- `scripts/task131-wolai-aline-sidebar-b1-smoke.js`：固化 B1，初始失败于本地侧栏 `240px`，GREEN 后覆盖 `248px`、`rgb(245,245,245)`、无 right inset、topbar 贴合。
- `scripts/task132-wolai-aline-sidebar-phase-b-smoke.js`：固化 B2-B10，使用父子页面 fixture 覆盖 header、快捷入口、行密度、选中态、层级缩进、hover action、上下文菜单、footer。
- `scripts/task133-wolai-aline-sidebar-tree-icons-arrows-smoke.js`：固化 B11，RED 失败于页面树统一房子 glyph；二次 GREEN 后断言 page 模式不渲染通用房子/伪 icon、不保留空 icon 槽，标题贴近箭头/占位，toggle 使用 20x20 SVG chevron。

实现摘要：

- `rust/crates/mnote-web/src/ssr/styles.rs`：侧栏宽度/背景、header、quick actions、tree row、选中态、context menu、footer 的 Wolai 对齐样式；page 模式无真实 icon 数据时不显示统一房子 glyph，也不保留空 icon 槽。
- `rust/crates/mnote-web/src/ssr/pages/layout.rs`：页面树运行时渲染补 `aria-current` / `aria-selected`，hover action 收敛为“更多/新建”，上下文菜单命令与 Wolai 对齐，运行时递归 depth；page tree 展开箭头改为 20x20 SVG chevron，page 行不渲染空 icon 节点。
- `rust/crates/mnote-web/src/tree_shell/page_renderer.rs` / `routes/tree.rs`：SSR 页面树补父子层级 depth / aria-level 语义，兼容 `parentId` 与 `parentNodeId`；SSR page tree 展开箭头同样使用 20x20 SVG chevron，page 行不渲染空 icon 节点。

验证命令：

- `cargo fmt -p mnote-web --check`
- `cargo check -p mnote-web`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task131-wolai-aline-sidebar-b1-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task132-wolai-aline-sidebar-phase-b-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task133-wolai-aline-sidebar-tree-icons-arrows-smoke.js`
- `node scripts/task119-rust-web-wolai-visual-regression-smoke.js`

证据路径：

- B1 Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task131-sidebar-b1-baseline/wolai-sidebar-b1-open-1392x1213.png`
- B1 本地最终：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task131-sidebar-b1-postfix/local-sidebar-b1-postfix-1392x1213.png`
- Phase B Wolai 基线矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b-baseline/comparison-matrix.md`
- Phase B 本地主线程最终：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b/local-sidebar-phase-b-1392x1213.png`
- Phase B 本地菜单最终：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b/local-sidebar-phase-b-menu-1392x1213.png`
- Phase B subagent post-fix2 JSON：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b-postfix2/sidebar-phase-b-postfix2-measurements.json`
- Phase B subagent Wolai 菜单：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b-postfix2/wolai-sidebar-context-menu-1392x1213.png`
- Phase B subagent 本地菜单：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b-postfix2/local-sidebar-context-menu-1392x1213.png`
- B11 用户指出差异截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b-baseline/wolai-03-page-tree.png` / `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task132-sidebar-phase-b-baseline/local-03-page-tree.png`
- B11 subagent 基线矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task133-sidebar-tree-icons-arrows-baseline/comparison-matrix.md`
- B11 subagent Wolai / 本地复核截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task133-sidebar-tree-icons-arrows-baseline/wolai-sidebar-tree-icons-arrows.png` / `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task133-sidebar-tree-icons-arrows-baseline/local-sidebar-tree-icons-arrows.png`
- B11 本地主线程最终截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task133-sidebar-tree-icons-arrows/local-sidebar-tree-icons-arrows-1392x1213.png`
- B11 二次复核矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task134-sidebar-arrow-no-empty-slot-baseline/comparison-matrix.md`
- B11 二次复核截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task134-sidebar-arrow-no-empty-slot-baseline/wolai-sidebar-tree.png` / `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task134-sidebar-arrow-no-empty-slot-baseline/local-sidebar-tree.png`

主线程复核结论：

- B1-B11 可量测项已对齐或按 checklist 明确保留本地差异。
- Wolai header/avatar DOM 选择器不稳定，最终以截图 + 本地稳定锚点复核。
- `Explorer` 是 mnote 本地创新入口，按 B10 保留；视觉不抢“我的页面”主路径。
- 菜单位置因页面树数据不同而不同；尺寸、项目、分组高度已对齐。
- Wolai 页面树图标是每行不同的私有 glyph；当前本地 projection 没有真实 per-page icon 数据，因此不硬编码类似图标，也不保留空白 icon 列。二次复核确认：保留空列会让标题 x 更接近 Wolai，但视觉上是明显缺失；当前按用户确认的产品判断去空列，残留差异是标题比 Wolai 真实图标+标题组合更靠左。后续若树投影提供真实 icon 字段，再按行渲染。

## 6. Phase C：顶栏、breadcrumb、搜索


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| C1 | PARITY | 顶栏高度与按钮密度 | `task135` 覆盖顶栏约 40px、右侧按钮组无搜索入口、icon 不再渲染成黑色方块；`task119` 复核 topbarHeight=40 |
| C2 | PARITY | breadcrumb | `task135` 覆盖 breadcrumb 当前标题绑定、弱色分隔符改为 Wolai chevron；真实父路径数据仍依赖后续 Page Aggregate / tree projection |
| C3 | PARITY | owner/published 按钮分型 | `task135` 覆盖 owner 顶栏绿色 `全网公开`，右侧按钮组从本地 AI/搜索收敛为 Wolai owner 态常见按钮序列 |
| C4 | PARITY | 顶栏搜索入口基线纠偏 | 2026-04-30 Wolai owner 当前 viewport 顶栏无搜索入口；本地已移除顶栏搜索按钮，搜索统一走侧栏入口 / `Ctrl+P` |
| C5 | PARITY | 侧栏搜索入口 | `task135` 覆盖侧栏左上搜索打开同一个全局搜索 modal，URL 不变；modal 打开时再次点击侧栏搜索会关闭 |
| C6 | PARITY | 搜索 modal 默认状态 | `task135` 按最新 Wolai 实测修正：空 query 先显示最近浏览，不直接显示筛选；输入后 switch 出现，`仅匹配标题` / `页面内搜索` 为 switch 且默认关闭 |
| C7 | PARITY | 搜索 modal 关闭路径 | `task135` 覆盖 Esc、主区域遮罩、再次 `Ctrl+P`、侧栏入口 toggle；URL 均不变 |
| C8 | PARITY | 搜索结果行 | `task135` 覆盖后台 API 结果、匹配数量、红色命中高亮、快捷键提示、结果 icon、结果 owner 标记 |
| C9 | PARITY | 搜索空态/加载态 | `task135` 覆盖空 query 最近浏览、输入后 loading、无结果 `没有搜索结果`，DOM 可断言 `data-search-loading` / `data-search-empty` |
| C10 | PARITY | 搜索入口/快捷键矩阵 | `task135` 和 subagent baseline 确认：侧栏搜索 / `Ctrl+P` 是搜索入口；`Ctrl+K` 按当前 Wolai 实测不打开搜索 |
| C11 | PARITY | 搜索结果 fixture | `task135` 固定本地 `Rust` / `Hermes` fallback fixture，并断言 modal 调用 `/api/search/documents` 而不是 DOM 前端过滤 |


### 6.1 task135 Phase C 执行记录

2026-04-30 已完成 Phase C：顶栏、breadcrumb、owner/published、搜索入口与搜索 modal。执行口径按 `wolai-aline` skill：subagent 先取 Wolai / 本地基线，主线程复核截图后补 RED smoke；实现后本地 smoke 通过，并已派 subagent 做 post-fix 复测。

RED：

- 新增 `scripts/task135-wolai-aline-phase-c-smoke.js`，初始失败于顶栏高度 `44px`、公开态文案 `Public`、顶栏多搜索入口、搜索 modal 未调用 `/api/search/documents`。
- subagent 基线纠偏：当前 Wolai `Ctrl+K` 不打开搜索；空 query 不直接显示筛选控件；输入后 `仅匹配标题` / `页面内搜索` switch 本次实测为关闭态。

GREEN：

- `rust/crates/mnote-web/src/ssr/pages/layout.rs`：顶栏公开态改为 `全网公开`，移除顶栏搜索入口，右侧按钮组对齐 owner 态；侧栏搜索入口改为 toggle；搜索 modal 输入改为 `type=search`，空 query 显示最近浏览，输入后调用 `/api/search/documents`，结果区标记 `data-search-results-owner="rust-kernel"`。
- `rust/crates/mnote-web/src/ssr/styles.rs`：顶栏高度收敛到 40px；搜索遮罩支持侧栏入口穿透 toggle，同时保留主区域遮罩关闭；补齐右侧按钮与结果图标 mask，避免黑色方块；搜索高亮统一红色弱底。
- `rust/crates/mnote-web/src/routes/search.rs`：fallback 搜索数据补 `Hermes` / `技能知识图谱开发` fixture，避免本地结果态依赖随机工作区数据。
- `scripts/task128-rust-web-wolai-search-modal-smoke.js`：同步当前 Wolai 基线，改为侧栏 / `Ctrl+P` 入口和 switch 默认关闭。

验证命令：

- `cargo fmt -p mnote-web --check`
- `cargo check -p mnote-web`
- `cargo build -p mnote-web --bin mnote-web`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task135-wolai-aline-phase-c-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task128-rust-web-wolai-search-modal-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task125-rust-web-search-server-first-smoke.js`
- `node scripts/task119-rust-web-wolai-visual-regression-smoke.js`

证据路径：

- Phase C subagent 基线矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task135-phase-c-baseline/comparison-matrix.md`
- Wolai Hermes 搜索基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task135-phase-c-baseline/wolai-search-hermes.png`
- 本地 Phase C 最终截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task135-phase-c/local-phase-c-search.png`；post-fix subagent 本地复核：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task135-phase-c-postfix/local-10-query-hermes.png`
- 本地搜索 modal smoke 截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/local-search-modal/local-3000-search-modal.png`

主线程复核结论：

- 搜索不再只是 UI 壳：modal 输入会调用 `/api/search/documents`，请求体包含 query 和 switch filter，结果区有 `data-search-results-owner="rust-kernel"`。
- 当前 Wolai 基线推翻了旧 checklist 的两个假设：`Ctrl+K` 不是搜索入口；`仅匹配标题` / `页面内搜索` 在本次输入态实测为关闭态。
- 本地 `Hermes` fixture 只能证明结果态结构、后台链路和高亮；不代表本地已经有 Wolai 真实空间数据。
- 顶栏/breadcrumb 的父路径层级仍受本地 Page Aggregate / tree projection 数据限制；本阶段只完成控件、入口、状态和同步锚点的对标。
- post-fix subagent 复测矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task135-phase-c-postfix/comparison-matrix.md`；复核确认本地右上角不再有黑色方块，侧栏搜索 toggle、`Ctrl+P` toggle、`Ctrl+K` 不打开、空 query 最近浏览、后台搜索 API、结果 icon/高亮均通过。

## 7. Phase D：文档画布与阅读态


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| D1 | PARITY | 主内容列宽 | `task136` 覆盖普通文档主列 `760px`，大屏居中不贴左；移动端沿既有 media query 保持不溢出 |
| D2 | PARITY | 标题位置与样式 | `task136` 按 Wolai 基线收敛到 y≈108、`34px / 44px / 600`、颜色接近 Wolai |
| D3 | PARITY | 默认隐藏 meta/debug 行 | `task136` 断言普通文档默认不显示 workspace/已同步 meta、大号页面 icon、debug 文案和横线 |
| D4 | PARITY | 正文段落 | `task136` 覆盖正文 `16px / 24px`，标题到正文间距按 Wolai 基线加大 |
| D5 | PARITY | 任务块 | `task136` 固定 Tiptap fixture 并断言渲染后存在 `input[type=checkbox]`，尺寸 16px；补齐 kernel `todo` 类型到 Tiptap taskList 的转换 |
| D6 | PARITY | 引用/列表/标题块 | `task136` 覆盖 heading、blockquote、bulletList；补齐 `bullet_list_item` / `numbered_list_item` 映射避免降级段落 |
| D7 | PARITY | 右下角浮动入口 | `task136` 覆盖 AI / 帮助入口 40px、AI 在上、间距约 16px、底部留白约 44px，不遮挡正文 |
| D8 | PARITY | 阅读态和编辑态切换 | `task136` 覆盖标题 focus、编辑器 focus 后标题 y/x 不跳动；subagent baseline 同样确认点击后布局稳定 |
| D9 | PARITY | 普通文档首屏入口语义 | `task130` 已覆盖 RED/GREEN，subagent 最终对标复核通过：根页不再停在“打开当前页面”入口，直接出现 document shell + editor island |



### 7.1 task136 Phase D 执行记录

2026-04-30 已完成 Phase D：文档画布与阅读态。执行口径按 `wolai-aline` skill：subagent 先取 Wolai / 本地只读基线，主线程复核截图后补 RED smoke；实现后本地 smoke 与相关回归通过，并已派 subagent 做 post-fix 复测。

RED：

- 新增 `scripts/task136-wolai-aline-phase-d-smoke.js`，初始失败于本地文档主列 `880px`，后续增强断言捕获标题 y 偏低、标题到正文间距偏小、右下浮动入口间距/底部位置旧基线。
- 基线截图确认 Wolai 标题为 y≈108、`34px / 44px / 600`；普通文档无 workspace/已同步 meta 行和大号页面 icon；右下入口为 40px，AI 在帮助上方，按钮间距约 16px，底部留白约 44px。
- smoke 还暴露后台链路差异：保存 Tiptap fixture 后，`/api/documents/content` 返回 `todo` / `bullet_list_item` 等 kernel 规范化类型，但浏览器 bootstrap 只识别旧类型，导致任务块和列表降级为普通段落。

GREEN：

- `rust/crates/mnote-web/src/ssr/styles.rs`：文档主列收敛到 760px；标题改为 `34px / 44px / 600` 且 y≈108；普通文档隐藏页面大 icon 与 meta/debug 行；正文行高 24px；补 task checkbox、blockquote、list 样式；右下浮动入口减重为 40px，AI 在上、帮助在下，间距 16px、底部留白 44px。
- `rust/crates/mnote-web/src/routes/web_shell.rs`：`legacyBlockToTiptap` 同时识别旧类型和 kernel 规范化类型：`todo`、`bullet_list_item`、`numbered_list_item`、`blockquote`。
- `rust/crates/mnote-web/src/routes/editor.rs`：runtime block 类型映射同步兼容 kernel 规范化类型，避免编辑器链路继续把任务/列表块当成 media 或段落。
- `scripts/task119-rust-web-wolai-visual-regression-smoke.js`：按本次 Wolai 基线更新右下浮动入口顺序、间距和底部留白断言，避免旧 Stitch 目标覆盖当前实测。

验证命令：

- `cargo fmt -p mnote-web --check`
- `cargo check -p mnote-web`
- `cargo build -p mnote-web --bin mnote-web`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task136-wolai-aline-phase-d-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task121-rust-web-editor-island-hydration-smoke.js`
- `node scripts/task119-rust-web-wolai-visual-regression-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task128-rust-web-wolai-search-modal-smoke.js`
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task135-wolai-aline-phase-c-smoke.js`

证据路径：

- Phase D subagent 基线矩阵：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task136-phase-d-baseline2/comparison-matrix.md`
- Wolai Phase D 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task136-phase-d-baseline2/wolai-01-first.png`
- 本地 Phase D 最终截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task136-phase-d/local-phase-d-document.png`
- Phase D subagent post-fix：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task136-phase-d-postfix/comparison-matrix.md`

主线程复核结论：

- 本地文档画布主列、标题字号/行高/字重、标题 y、meta/icon/debug 隐藏、正文行高、任务/引用/列表渲染、右下浮动入口尺寸/顺序/间距已被 smoke 固化。
- subagent post-fix 在根文档截图中复核标题 y=108、列宽 760、字号 34/字重 600、meta/icon/debug 不可见、浮动入口 40px/16px/44px、点击后不跳动。
- 当前本地 fixture smoke 能证明后台内容链路不再把任务块和列表降级为普通段落；post-fix 根文档缺少任务/引用/列表内容，因此这三类块的真实视觉细节仍以后续 Phase E editable-test 或专门 fixture 页面继续细化。
- 剩余差异：本地页面标题来自临时 fixture，文案与 Wolai Hermes 不同；Wolai 真实 per-page icon 数据仍未进入本地 projection，按 Phase B 结论不伪造。

## 8. Phase E：主编辑器块交互


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| E0 | DONE | editable-test 焦点护栏 | Wolai Hermes editable-test 与本地 smoke 均断言写入前焦点在正文测试块，不在标题、breadcrumb 或隐藏输入 |
| E1 | DONE | editable-test 基础输入 | Wolai 已取输入/回车/撤销基线；本地 `task137` 覆盖三行输入、保存、刷新后保持 |
| E2 | DONE | 块 hover 手柄 | Wolai follow-up 基线确认默认 hover 只显示 `2x2` 四点手柄；本地 smoke 断言四点、可见性、与正文间距和从正文移向手柄不消失 |
| E3 | DONE | 上方插入加号 | 本地仅在 hover 四点上方热区时显示上方 `+`，点击可在目标块前插入并聚焦；tooltip/title 包含 `在上方插入块` / `Esc, a` |
| E4 | DONE | 下方插入加号 | 本地仅在 hover 四点下方热区时显示下方 `+`，点击可在目标块后插入并聚焦；tooltip/title 包含 `在下方插入块` / `Esc, b` |
| E5 | DONE | `Esc, a` / `Esc, b` | 本地块选中态快捷键可插入 before/after，并把输入焦点放入新块 |
| E6 | PARTIAL | 块菜单 | 本地点击四点后手柄切换为三横线；主菜单约 240px、浮在侧栏之上、位于三横线左侧且不遮挡正文/手柄；`转换为` 二级菜单已补齐 Wolai 当前基线项目，H4 小标题与页面转换已有真实命令；复制链接/颜色/文字翻译子菜单、折叠标题/折叠待办三级菜单仍需继续补齐 |
| E7 | DONE | slash 菜单 | 本地 `/` 跟随编辑器打开；含 `AI 助理 / 用 AI 写作 / 基础块列表 / 文本 / 待办列表 / /h1`，方向键/Enter 选择仍由 smoke 覆盖 |
| E8 | DONE | selection toolbar | 本地选中文本出现工具条；粗体、斜体、链接、颜色、转换块入口可见，入口文案已中文化 |
| E9 | PARTIAL | `Ctrl+A` 双阶段选择 | 本地 smoke 覆盖第一次/第二次选择范围扩展；Wolai 的多块粉色选区视觉与块级全选细节后续单列视觉对标 |
| E10 | DONE | 拖拽预览 | 本地 smoke 覆盖拖动手柄时 `.block-drop-indicator` 横向 drop line 可见；分栏竖线预览与落点持久化后续单列 |

### Phase E 执行记录（2026-04-30）

- Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-phase-e-baseline/comparison-matrix.md`，截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-phase-e-baseline/screenshots/`。
- Wolai 说明页摘要：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-phase-e-baseline/doc-summary.md`。
- 本地 post-fix smoke：`MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-phase-e-local-smoke node scripts/task137-wolai-phase-e-smoke.js`，通过。
- Subagent post-fix 复核：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-phase-e-postfix-subagent-final3/`，通过。
- 手柄 follow-up Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-handle-followup-wolai-baseline/`，确认默认四点、上/下热区分别出 `+`、点击后变三横线、菜单在正文左侧不挡正文。
- 手柄 follow-up 本地 smoke：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-handle-followup-local-postfix10/`，通过并覆盖四点、上下加号、可达性、菜单不挡正文/手柄。
- 手柄 follow-up subagent 本地复核：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task137-handle-followup-local-subagent-postfix/`，通过；复核默认四点、上下加号、正文到手柄不消失、点击后三横线、菜单不遮挡正文/手柄。
- 关键截图：`02-hover-handle-default.png`、`02a-hover-handle-before-plus.png`、`02b-hover-handle-after-plus.png`、`04-drag-preview.png`、`05-block-menu.png`、`07-slash-menu.png`、`08-toolbar.png`。`05-block-menu.png` 已断言菜单不遮挡正文且不盖住三横线手柄；更多 Wolai 菜单项后续补齐。
- 块菜单 refresh Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task138-phase-e-wolai-refresh/`，确认二级/三级菜单、Esc/外部点击关闭、鼠标移出保持打开。
- 块菜单 refresh 本地 smoke：`MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task138-phase-e-local-smoke-10 node scripts/task137-wolai-phase-e-smoke.js`，通过；覆盖第二行手柄不跳行、240px 菜单、底部编辑信息、转换子菜单缺失项、鼠标移出保持、Esc 关闭、H4 真实转换。
- 块菜单 refresh subagent 本地复核：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task138-phase-e-local-subagent-postfix/`，通过；复核第 1-4 行手柄不跳行、菜单未被侧栏裁剪、鼠标移出保持、Esc/外部点击关闭、H4 真实转换。
- `转换为 -> 页面` task139 本地实现曾只做原地伪页面块；该结论已被用户复核纠偏，不能作为完成口径。后续以 task140 Wolai 真源基线为准：转换必须产生/绑定真正子页面，页面树可见且点击页面块可打开。
- `转换为 -> 页面` task140 Wolai 真源基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task140-transform-page-true-source-wolai-baseline/`；确认父页 URL 当下不变，当前块原地变 page block，点击后打开真实子页面 `5ZNTivwkmVyRSGN3AAntqJ`，返回父页后页面树 `软件开发 -> Hermes` 下可见同名子页面。
- `转换为 -> 页面` task140 本地 smoke：`MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task140-transform-page-true-source-local-smoke-4 node scripts/task137-wolai-phase-e-smoke.js`，通过；覆盖 `/api/tree/commands` create、`parentId=当前文档`、返回 `documentId`、页面块 href 指向子页面、点击后进入子页面、刷新后页面树出现同名子页面。
- `转换为 -> 页面` task140 subagent 本地复核：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task140-transform-page-true-source-local-subagent-postfix/`，通过；关键断言 child documentId 存在、`parentId` 指向当前文档、父页 URL 不立即变化、点击页面块进入子页面、页面树可见同名子页面；主线程复核截图 `06-transform-page.png` / `09-transform-page-open-child.png` 未见 true-source 语义差异。
- 代码改动：`rust/spikes/leptos-tiptap-spike/src/lib.rs` 与生成的 `rust/spikes/leptos-tiptap-spike/generated/island/*`；`scripts/task137-wolai-phase-e-smoke.js` 已在本地 ignored smoke 中升级真源断言，默认不入库。
- 验证命令：`cargo fmt --check`、`cargo check`、`node wolai-frontend/scripts/build-leptos-tiptap-island.js`、`node scripts/task137-wolai-phase-e-smoke.js`、`node scripts/task121-rust-web-editor-island-hydration-smoke.js`、`node scripts/task136-wolai-aline-phase-d-smoke.js`。

### Phase E 参考 Tiptap 审计记录（2026-04-30）

- `tiptap-notion-like-registry` / `tiptap-notion-like-template` 包含 197 个 registry 组件，核心能力不是单个菜单，而是 `DragContextMenu`、`SlashDropdownMenu`、`NotionToolbarFloating`、AI、颜色、链接、表格、图片、TOC、缩进、节点背景、节点对齐、emoji、mention、协作和移动端 toolbar 的组合。
- `leptos-tiptap` 当前已支持 `starter-kit` 与 `full`：blockquote、bold、bullet/ordered/task list、code/codeBlock、heading、history、horizontalRule、italic、strike、text-align、highlight、image、link、placeholder、youtube；未直接覆盖表格、数学、emoji、mention、TOC、AI、collaboration caret、节点背景、节点对齐、缩进和 UniqueID。
- Phase E 后续实施按 Wolai 基线优先级拆小任务；参考 Tiptap 能力先进入 checklist，不直接视为 mnote 必须一次性照搬。
- E11-E31 统一改为“参考 Tiptap 来 aline mnote”：每个任务先定位 `tiptap-notion-like-registry` / `tiptap-notion-like-template` 的组件、hook、extension 或 `leptos-tiptap` bridge 命令，再对照 Wolai 实测决定 mnote 的最小实现。不得绕过已有 Tiptap 参考自行造一套同类 UI 或命令。
- 旧 E16 / E24 / E28 中分散的颜色、背景色、link popover、floating toolbar 能力已合并为 E15-E17 的统一能力包；后续实现颜色相关功能时优先参考 `ColorMenu`、`NodeBackground`、`highlight` / `link` bridge，不再分别在 selection toolbar、drag menu、floating toolbar 中重复造轮子。

### Phase E Tiptap 参考优先 backlog

执行规则：E11-E31 中任何一项进入实现前，必须先在任务记录中写出参考路径、可复用代码点、mnote 真源落点和 Wolai-aline smoke 断言。若参考实现不适合直接复用，需要说明不复用的原因。

### Phase E Tiptap 参考执行记录（2026-05-01）

- E11 参考入口已固化：`tiptap-notion-like-registry/materialized/tiptap-ui/*`、`tiptap-notion-like-registry/materialized/tiptap-extension/*`、`tiptap-notion-like-template/tiptap-notion-like-template/src/components/tiptap-*`、`leptos-tiptap/src/api/commands.rs`。后续 E13-E31 实现前必须先写参考路径和不复用原因。
- E12 bridge 边界：`rust/spikes/leptos-tiptap-spike` 以 `leptos-tiptap` `features=["component", "full"]` 编译；可直接复用的命令包括基础块转换、`set_horizontal_rule`、`toggle_task_list`、`toggle_bullet_list`、`toggle_ordered_list`、`set/toggle_text_align`、`set/toggle_highlight`、`set/toggle_link`、`set_image`、`set_youtube_video`、history 与通用 `insert_content(_at)`。
- E12 缺口边界：TableKit 已补最小 table schema、行列/标题行列/隐藏边框命令和保存链；完整 TableHandle、TableSelectionOverlay、列宽拖拽、fit、数据表格、Mention、Emoji、TOC、AI、UniqueID/anchor、NodeBackground、NodeAlignment、Indent、ListNormalization 仍不在 `leptos-tiptap` bridge 直接能力内；进入实现时优先扩 bridge 或落 mnote tree/page 命令，不允许只加前端临时 DOM 状态。
- E13 Wolai slash 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task142-e13-slash-wolai-baseline/report.md`；Wolai 菜单为 fixed 弹层约 `315x400`，首屏分组 `AI 助理 /ai`、`基础块列表 /jichukuai`，完整分组还包括进阶块、脚注/注释、快速分栏、转换为、媒体与附件、第三方应用、快速输入、插入引用、行内块、快速功能、文字颜色、背景色、荧光背景色；包含分割线、简单表格/数据表格、图片、页面目录、Emoji，未见明确 mention。
- E13 当前本地 slash 状态：`rust/spikes/leptos-tiptap-spike/src/lib.rs` 的 `SLASH_ACTIONS` 已包含 `分割线` 与 `简单表格 /jdbg`，分别走 `editor.set_horizontal_rule()` 和真实 Tiptap table 插入；参考 template `components/tiptap-node/horizontal-rule-node/*`。本地与 Wolai 明确缺口是页面 `/ym`、折叠块、页面目录 `/toc`、数据表格 `/db`、Emoji `/bq`、颜色分组、插入引用和行内块；图片 `/tp` 已进入 E24 最小真源切片，但上传/最近上传/浮动工具条仍未完成。
- E13 分割线真源闭环：2026-05-01 已补 `EditorBlockType::Divider`、`TiptapNode::HorizontalRule`、`mnote-web` bootstrap `divider -> horizontalRule` 恢复、bridge `horizontalRule -> divider` 保存、JS bridge `Map -> Object` 规范化，以及从 `conflictDetectionKey` 后缀恢复 revision；本地 smoke 已断言 slash 点击后 `/api/documents/content` 返回 `divider`，刷新后 ProseMirror 仍有 `<hr>`。主线程通过截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task143-e13-divider-persistence-local-v8`；subagent 后验通过截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task143-e13-divider-persistence-subagent`。
- E15/E16 当前本地 toolbar 状态：`rust/spikes/leptos-tiptap-spike/src/lib.rs` 中 `mnote-leptos-tiptap-toolbar` 已用 `toggle_bold/italic/strike/code`、`toggle_mark(Underline)`、`set/toggle_link`、`set_color/unset_color`、`set_highlight/unset_highlight`、`set_text_align` 等 bridge 命令；参考路径为 `tiptap-ui/color-menu/*`、`color-text-button/*`、`color-highlight-button/*`、`mark-button/*`、`text-align-button/*`。缺口是 node background、recent colors、drag menu 颜色子菜单复用、完整 link popover、AI、sup/sub、indent/outdent。
- E19 列表缩进真源闭环：2026-05-01 已按 Wolai Hermes 基线确认 `Tab` 会把第二个列表项挂到父项 `sub-node-container`，`Shift+Tab` 提升回同级，不只是视觉 padding。参考路径为 `tiptap-extension/indent-extension.ts`、`list-normalization-extension.ts` 与 `leptos-tiptap/src/api/commands.rs` 的 `sink_list_item` / `lift_list_item`；本地已有 Tiptap 列表键盘命令，修复点落在 `core-protocol` Tiptap bridge 与 `bridge-runtime` canonical legacy content，保存时保留 `childBlockIds` / `children`，`mnote-web` bootstrap 可从 legacy `children` 恢复嵌套 Tiptap 列表。Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task144-e19-indent-wolai-baseline/comparison-matrix.md`；本地 smoke：`MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task144-e19-indent-local-green-final node scripts/task144-e19-indent-list-smoke.js`，通过并覆盖 Tiptap JSON、`/api/documents/save`、`/api/documents/content` 真源和刷新恢复。
- E20 块布局/文字居中局部闭环：2026-05-01 已按 Wolai Hermes 基线确认 `Ctrl/Cmd+Shift+U` 会进入块布局选中态，块菜单存在 `文字居中`，点击后 Wolai 视觉居中且刷新后保持；Wolai DOM 语义表现为内部内容 class `_1PQWZ`，不是根块 `text-align:center`。本地当前实现 `Ctrl+Shift+U` 后显示 `data-testid=block-layout-outline` 虚线轮廓，并采用 `leptos-tiptap` `set_text_align(TiptapTextAlign::Center)` 作为 Tiptap 参考优先的文字居中真源实现；保存请求、`/api/documents/content` 与刷新恢复均保留 `textAlign=center`。Wolai 基线：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task145-e20-alignment-wolai-baseline/precise-summary.json`；本地 smoke：`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_PHASE_E_SCREENSHOT_DIR=/mnt/Data1T/mnote/tmp/wolai-editor-parity/task145-e20-layout-align-local-current node scripts/task145-e20-alignment-smoke.js`。剩余拆分：selection toolbar 当前 Wolai 基线未出现对齐入口，拖拽分栏/节点级对齐尚无有效 Wolai 基线，后续不能把 E20 标 DONE。
- E21 页面当前类型勾选态与 slash 拼音入口局部闭环：2026-05-01 `task137-wolai-phase-e-smoke.js` 已覆盖 `转换为 -> 页面` 后二次打开块菜单时 `block-transform-item-page` 的 `data-current=true` 与 `✓` 勾选态；本轮复跑通过截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task146-e21-current-state-regression`。同日新增 slash 查询态 smoke：输入 `/` 后继续输入 `zhw`，本地菜单显示 `转换为 /zhw`，对应 Wolai slash 基线 `task142-e13-slash-wolai-baseline` 中 `转换为 /zhw`；RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task146-e21-slash-zhw-red`，GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task146-e21-slash-zhw-green`。2026-05-01 继续补 `页面 /ym` 查询入口，Wolai 基线同目录 `04-slash-menu-candidates.json` / `06-slash-menu-rows.json` 均包含 `页面 /ym`；本地 RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task147-e21-slash-ym-red`，GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task147-e21-slash-ym-green`。同日补 H4 小标题二次打开当前态：RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task148-e21-h4-current-red`，GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task148-e21-h4-current-green`，当前项写入 `data-current=true` 并显示 `✓`。同日补基础转换快捷键 `Ctrl/Cmd+Shift+1/2/3/5/6/7` 的本地命令映射，RED 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task149-e21-hotkey-h1-red`，GREEN 截图目录 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task149-e21-hotkey-h1-green`。当前 `/zhw` 与 `/ym` 入口只作为 Wolai slash 分组入口展示，真实转换/页面创建仍走块菜单或选区工具栏，后续需补 Wolai 二次勾选态基线和其余类型全量当前态。
- E22 折叠标题局部闭环：2026-05-01 复用 Wolai Hermes `task138-phase-e-wolai-refresh` 基线，确认 `转换为 -> 折叠标题` 会展开三级菜单 `折叠主标题/折叠大标题/折叠中标题/折叠小标题`，不是 disabled 文案。本地已补 `leptos-tiptap` heading `collapsed` attr、`core-protocol` Tiptap bridge、`bridge-runtime` legacy props、`mnote-web` bootstrap 和块菜单三级菜单；`task150-e22-folding-blocks-smoke.js` 覆盖点击 `折叠主标题` 后 h1 `data-collapsed=true`、保存请求 `attrs.collapsed=true`、`/api/documents/content` 真源和刷新恢复。当前只完成折叠标题最小切片，折叠待办/折叠列表和折叠后的子块显隐状态仍需后续拆分。
- E23 简单表格局部闭环：2026-05-01 Wolai Hermes 可编辑基线已确认 `简单表格 /jdbg` 默认插入 `4x3` HTML `<table class="table-content">`，外层 `data-block-type="table"`，URL 不变；行侧/列顶 aux 点击会插入行/列并呈现淡红 overlay，选项菜单含标题行/标题列/隐藏边框线 switch，未确认到清空/fit。当前本地已对齐 slash `简单表格 /jdbg`，并通过 bridge 调用 Tiptap 官方 `insertTable({ rows: 4, cols: 3, withHeaderRow: false })` 插入 `4x3` 真实 Tiptap table，并补表格 toolbar 的下方插入行、右侧插入列、清空当前单元格、删除行/列/表格；已补 `选项` 菜单，`标题行`、`标题列`、`隐藏边框线` 均使用 `role="switch"` 和 `aria-checked`，切换后写入 `tableHeader` 节点或 `attrs.hiddenBorders=true`。已补表格行侧/列顶 aux controls 和最小 TableSelectionOverlay：`table-row-aux-*` 点击后从 `4x3` 进入 `5x3`，`table-col-aux-*` 点击后进入 `5x4`，并显示 `data-testid="table-selection-overlay"` 淡红覆盖层，toolbar 保持可用。2026-05-01 继续补列宽拖拽：Tiptap table 开启 `resizable=true`，列宽拖拽回到官方 `columnResizing` 路径；拖拽首列右边缘后写入单元格 `attrs.colwidth`，保存请求、`/api/documents/content` 与 reload 后 DOM 宽度/col 样式均由 `task151-e23-table-smoke.js` 覆盖；保留 `MnoteTableView` 作为 mnote 属性同步适配，避免 resizable node view 丢失 `data-hidden-borders` / `data-block-id`。2026-05-01 继续补真实 ProseMirror TableSelection：bridge 增加 `select_table_row` / `select_table_column` 命令，行侧/列顶 aux 插入后同步 Tiptap 官方 `CellSelection.rowSelection` / `CellSelection.colSelection`，smoke 断言目标行/列 `.selectedCell` 数量和位置，并静态断言不再使用 `setCellSelection` 或手写 `simple_table_node()` 插入路径；同时把 `@tiptap/pm/tables` 纳入 shared hosted modules，避免 tableEditing decorations 与 EditorView 跨 bundle 混用。Wolai 基线截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-wolai-tablekit-baseline/`；本地列宽版截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-table-resize-green`；本地官方 resize 复核截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-official-resize-green`；本地官方 TableKit 命令复核截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-official-tablekit-commands-green`；本地真实 TableSelection 截图：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task151-e23-table-selection-green`；回归截图：`task144-e19-regression-after-e23-resize`、`task145-e20-regression-after-e23-resize`、`task150-e22-regression-after-e23-resize`、`task137-phase-e-regression-after-e23-resize`。
- E24 图片最小真源闭环：2026-05-01 已按 Wolai E13 slash 基线确认 `媒体与附件` 分组存在 `图片 /tp` 与 `最近上传图片 /tp`；第一段实现 `图片 /tp` 最小切片，参考 `leptos-tiptap` 官方 `TiptapImageResource` / `set_image` bridge（`src/api/types/extensions/image.rs`、`src/api/commands.rs`、`tiptap/src/extensions/tiptap_image.ts`）与 template `components/tiptap-node/image-node/*`、`image-upload-node/*`，不手写 image JSON。当前本地 `SLASH_ACTIONS` 已补 `图片 /tp` 和 `媒体与附件` 分组，`p0_extensions()` 显式启用 `TiptapExtension::Image`，点击后调用 `editor.set_image(TiptapImageResource { ... })` 插入真实 Tiptap `image` 节点；`core-protocol` 新增 `EditorBlockType::Image` / `TiptapNode::Image`，`bridge-runtime` 保存为 legacy `image` 且保留 `props.tiptapImage`，`mnote-web` bootstrap 从 content API 恢复为 `<img>`；本地只读占位资源走 `/api/editor/image-placeholder.svg`，避免 smoke 依赖外网或破图。第二段补图片点击选中态与图片专用 floating toolbar，参考 `tiptap-notion-like-registry/materialized/tiptap-node/image-node/image-node-floating.tsx`、`image-node-extension.ts`、`tiptap-ui/image-align-button/use-image-align.ts`、`tiptap-ui/image-download-button/use-image-download.ts`：本地点击 `<img>` 后展示 `image-floating-toolbar`，提供左/中/右对齐和同源图片下载，删除入口本切片保持禁用；图片对齐通过 `Image.extend({ addAttributes: { "data-align" } })` 扩展官方 Image schema 后调用 `editor.update_attributes(TiptapSchemaTarget::Node(TiptapNodeName::Image), ...)`，不是 UI 伪样式；同源下载只读当前 NodeSelection 图片 DOM 的 `src/title/alt`，用隐藏 `<a download>` 触发，不触发保存链。`task152-e24-image-smoke.js` 覆盖 slash 入口、DOM `<img>`、图片实际加载、图片 toolbar、同源下载事件、删除入口禁用态、居中对齐 `data-align`、保存请求 `tiptapDocument`、`/api/documents/content` image 真源与 reload 恢复；通过截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task152-e24-image-download-green`。剩余：真实上传、最近上传图片、caption、resize、replace、跨源下载 fallback、删除保存链、移动端 toolbar、上传失败态另拆后续。

- E25 TOC 最小真源闭环：2026-05-01 已按 Wolai slash 基线确认 `页面目录 /toc`，并参考 `tiptap-notion-like-template/src/components/tiptap-node/toc-node/*`、`toc-show-title-button/*`、`toc-sidebar/*` 与 `notion-like-editor.tsx` 中 `TableOfContents.configure({ onUpdate })` 的数据链路。当前本地先完成第一段：`leptos-tiptap` 新增 `toc_node` bridge 扩展，真实 Tiptap schema 名为 `tocNode`，slash `页面目录 /toc` 调用 `editor.insert_toc_node(TiptapTocNodeAttrs { top_offset: 0, max_show_count: 20, show_title: true })`，不是普通 div 或手写 spike JSON；NodeView 从当前 Tiptap doc 的 heading 节点派生目录项，支持点击目录项定位并更新 hash，支持标题显示开关并通过 `updateAttributes("tocNode", { showTitle })` 持久化。保存链新增 `EditorBlockType::Toc` / `TiptapNode::TocNode`，`bridge-runtime` legacy content 保留 `props.tiptapTocNode`，`mnote-web` reload 恢复 `tocNode`；`task153-e25-toc-smoke.js` 覆盖 `/toc` 入口、真实 tocNode DOM、heading 列表派生、动态 heading 更新、点击定位、标题开关、保存请求、content API 和 reload 恢复。截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task153-e25-toc-local-smoke`。剩余：接入 Tiptap 官方 `@tiptap/extension-table-of-contents` v3 数据源或完成等价 bridge 评估、TOC sidebar、active heading 高亮、完整块菜单标题开关入口、Wolai 像素级视觉、移动端行为、UniqueID/anchor 统一化。
- E26 执行前口径纠偏：2026-05-02 已按 `5-2`、`5-4`、`5-5`、`5-6` 和 `5-7` 设计确认，E26 不是“前端引入 Tiptap UniqueID 即完成”。正式块身份必须来自 Rust `EditorBlock.block_id`，经 Tiptap bridge 映射为 `data-block-id` 供浏览器 runtime 使用，再通过 `page.body.save` 写回 Convex-backed 持久化底座；复制锚点和 hash 定位只能消费这个真源 id。Tiptap `UniqueID` 可以参考其节点身份策略，但不得生成长期块 id、不得绕过 Rust `EditorBlockDocument`、不得绕过 Page Aggregate / `page.body.save`。
- E26 执行边界：实现与 smoke 必须把 `EditorBlockDocument -> Tiptap attrs.blockId/data-block-id -> DOM 锚点 -> page.body.save -> /api/documents/content -> reload/hash 定位` 串成一条链。允许在浏览器 runtime 内用 `UniqueID` 或等价插件帮助定位节点，但只能读取/补齐已有 Rust block id；若某块缺少正式 id，应通过 Rust/保存适配链生成并持久化，而不是让前端临时 id 成为长期合同。Convex 只验证持久化结果可读可刷新，不作为语义真源。
- E26 最小真源闭环：2026-05-02 已完成第一段 anchor 切片。`leptos-tiptap` paragraph/heading/blockquote/codeBlock/image/table 的 `blockId` 渲染同时输出 `data-block-id` 与 DOM `id`，浏览器 hash 命中走 `id=:blockId` + CSS `:target`，不是手工给 ProseMirror DOM 写临时 class；Rust runtime 复制链接和 hash 滚动继续只消费 `EditorBlock.block_id` 派生的 `attrs.blockId`。`mnote-web` 保存 payload 不再发送空 `content: []`，而是派生 `editorDocument`、legacy `content`、`tiptapDocument` 和 `blockCount` 写回 Convex-backed 持久化底座；reload 侧 legacy block 恢复继续补 `attrs.blockId`。本地 smoke `node scripts/task154-e26-anchor-smoke.js` 已覆盖保存请求、`/api/documents/content`、复制链接、DOM `id/:target` 和 reload/hash 定位，截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task154-e26-anchor-local-smoke`。剩余：列表项/分割线等更多块类型的统一 anchor attr 覆盖、Wolai 视觉细节、块引用/页面引用预览与移动端行为另拆后续。
- E27 执行前口径纠偏：AI 编辑能力包不是“补 AI 菜单文案”或“点击后显示 feedback”。最小闭环必须从 `leptos-tiptap` 的 slash / 块菜单入口出发，携带当前 `documentId`、`workspaceId`、Rust `blockId`、selection 摘要和 Tiptap JSON 快照，进入 Hermes run/session context；Hermes 通过 mnote skill/plugin 调用稳定工具，再由 Rust runtime / `page.body.save` / Convex-backed content 链写回。2026-05-13 起长期口径进一步修正：`/api/ai-agent/run`、`openai-agents-python` sidecar 和 `mnote-cli host` 都只作为历史/兼容路径，不再代表页面 AI 长期主入口；`mnote-cli` 只可作为 mnote plugin 内部适配器或调试入口。E27 第一刀已完成的 sidecar / `/api/ai-agent/run` 路径只作为过渡基线，不宣称是长期主线。
- E27 AI agent 入口与写入闭环：2026-05-02 已完成历史主路径纠偏，修正此前把 `/api/hermes/bridge` 当作 E27 主入口的误导口径。块菜单 `AI 助理` 当时从当前 `leptos-tiptap` editor 读取 `documentId`、`workspaceId`、Rust `blockId`、selection state、selected text 与 `tiptapDocument` 快照，发起 `/api/ai-agent/run` 请求，payload 固定 `scope=document`、`stream=true`、`options.ai.provider=online`，并显示 `mnote-leptos-tiptap-ai-status` 的 `idle/pending/ready/error` 状态；请求上下文标记 `source=leptos-tiptap-island`、`action=ask_ai`，Next sidecar adapter 已透传 `workspaceId / selectedBlockId / selection / tiptapDocument` 等 block 级上下文给 `openai-agents-python`。本地 smoke `node scripts/task155-e27-ai-edit-smoke.js` 和 `node scripts/task156-e27-ai-writeback-smoke.js` 是历史执行命令，脚本现已迁入本机 gitignored `recycle/scripts/retired-ai-agent-run-smokes/`，只保留显式环境变量下的历史对照；截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task156-e27-ai-writeback-local-smoke`。2026-05-14 起，页面 AI 主入口改为 Hermes client proxy、上下文进入 Hermes run/session context、写入工具注册为 mnote Hermes plugin 的部分已由 `7-4` 完成；剩余为 Wolai AI 菜单视觉基线、slash AI/selection toolbar AI、Improve/continue/regenerate/summarize/translate 子命令、`doc_insert_blocks` 多块插入和标题写入等细分入口如何复用同一条 Hermes tool chain。
- E27 Auth 真源纠偏：2026-05-22 补充确认，AI 编辑和在线 smoke 的用户身份默认以 Rust SQLite control-plane session / actor 为主线；不同账号的数据隔离依赖 control-plane 解析真实用户与 workspace/share grant 权限链校验。`/auth` 复用当前 `mnote-web` 登录页和默认测试账号 `mnote.e2e@example.com` / `MnoteE2E123!`；`/api/session`、AI orchestrator 转发和 source-specific transport 均应真实 session / forwarded actor 优先。旧 Convex Auth 只作为历史在线 / compat / cloud source 验证边界。`DEV_USER_ID` / admin acting identity 只允许作为本地底层 fallback 或显式 `MNOTE_DEV_AUTH=1` 联调模式，不能作为 E27 在线验收、多账号隔离或正式数据真源。
- E27 当前推进备注：2026-05-03 主线程先切到 E28 Mention / Emoji，E27 曾暂停在 online smoke 模型网关层排障状态。2026-05-14 页面 AI 主入口已经完成 Hermes client proxy + mnote plugin/tool 迁移；恢复 E27 时应从 slash AI / selection toolbar AI / 子命令体验与真实 actor 复用这条新主链继续，不要回退成旧 orchestrator 或旧 `/api/ai-agent/run` 排障。
- E28/E29 暂停与 E30 先行口径：2026-05-03 主线程先暂停 E28 Mention / Emoji 与 E29 Comment / History，转入 E30 Menu / Floating 状态机能力包。E28 已有 Wolai Hermes baseline 显示正文输入 `@` 当前弹出提醒/会议/成员候选，并可插入成员 mention，不是页面引用搜索；证据目录为 `/mnt/Data1T/mnote/tmp/wolai-editor-parity/task157-e28-wolai-mention-baseline/`，恢复 E28 时需先重新定 `@mention` 口径，不要按“页面引用第一刀”继续。E29 在评论/历史后端边界未重新确认前保持暂停。E30 第一刀只收敛已有 slash、块菜单、二级菜单、selection/image/table floating toolbar 的打开互斥、Esc、外部点击、方向键、Enter 与层级收起，不扩新业务命令。
- E30 Menu / Floating 状态机第一刀：2026-05-03 已参考 `use-floating-element`、`use-menu-navigation`、`use-floating-toolbar-visibility` 的集中可见性/键盘/关闭模型，把本地已有 slash、块菜单、selection toolbar、image toolbar、table toolbar/options 的关闭与互斥收口到 `close_editor_floating_overlays*` 与 `open_*_overlay` 入口；`task158-e30-menu-state-smoke.js` 覆盖 slash `ArrowDown` active、Esc 关闭、块菜单二级菜单、selection color panel、image toolbar、table options、slash 打开关闭 selection toolbar、块菜单打开关闭 image toolbar。Wolai 基线目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task158-e30-wolai-baseline/`；本地主线程截图目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task158-e30-menu-state-local-smoke-main3`；本地 subagent 复测目录：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task158-e30-local-postfix-subagent`。剩余：Wolai slash / 块菜单二级菜单在只读条件下未稳定验证，Enter 选中、外部点击和更多三级菜单收起需后续 editable-test 小切片继续补。
- E31 Auth 入口回收：2026-05-04 已把 `3000` 的 `/auth` 收回为本地 `mnote-web` SSR 登录页，不再代理 3100；2026-05-22 起未登录访问 `/` 仍 303 到 `/auth`，已登录以 Rust control-plane session / actor 为准进入工作区，旧 Convex cookie 仅作为历史 compat 输入。`task159-auth-entry-smoke.js` 覆盖 `/auth` 本地 200、`/` 未登录 303、已登录 200、无第三方快捷登录/隐私政策文案，`task114-rust-web-gateway-entry-smoke.js` 与 `task117-next-retirement-guard.js` 已同步更新。截图待复核：`/mnt/Data1T/mnote/tmp/wolai-editor-parity/task159-auth-entry-baseline/`。


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| E11 | DONE | Tiptap 参考优先执行门 | 已固化：每个 Phase E 子任务先记录参考路径、可复用代码点、mnote 真源落点和 Wolai-aline smoke；参考入口覆盖 `registry/materialized/tiptap-extension/*`、`registry/materialized/tiptap-ui/*`、`template/src/components/tiptap-*`、`leptos-tiptap/src/api/commands.rs`，无参考路径不得直接实现 UI |
| E12 | DONE | `leptos-tiptap` bridge 能力边界 | 已盘点：当前 full bridge 覆盖基础块/行内 mark、history、horizontalRule、task/bullet/ordered list、text-align、highlight、image、link、youtube、table/tableRow/tableCell/tableHeader 最小 schema；仍缺 mention、emoji、TOC、AI、UniqueID、NodeBackground/Alignment、非列表 Indent/ListNormalization，后续按能力包判断扩 bridge、走 mnote 命令或暂缓 |
| E13 | PARTIAL | SlashDropdownMenu 能力包 | 参考 `tiptap-ui/slash-dropdown-menu/*` 与 template horizontalRule；本地已覆盖 AI 文案入口、基础块、待办、标题、列表、引述、代码、分割线、简单表格、图片，其中分割线已走 `set_horizontal_rule()`、保存为 kernel `divider`、刷新恢复为 `<hr>`，简单表格已走真实 Tiptap `table` schema，默认 `4x3` 并由 `task151-e23-table-smoke.js` 覆盖保存/刷新/基础行列、表格选项、行/列 aux 插入、selection overlay 和列宽拖拽持久化操作，图片 `/tp` 已走 `set_image` 并由 `task152-e24-image-smoke.js` 覆盖保存/刷新；Wolai 基线已确认还需补页面、折叠块、TOC、数据表格、Emoji、颜色、引用、行内块等分组，且每项需真实 schema/bridge 或明确未接入状态 |
| E14 | PARTIAL | DragContextMenu 能力包 | 以 `DragContextMenu` 为主参考重组块手柄菜单；当前四点/三横线、菜单位置、基础二级转换已对齐，后续补 copy/delete/copy anchor/reset formatting/Ask AI 等命令时复用同一菜单模型 |
| E15 | PARTIAL | NotionToolbarFloating 能力包 | 参考 `NotionToolbarFloating`；本地 selection toolbar 已接 TurnInto、bold/italic/underline/strike/code、link、color、text-align 的真实 Tiptap 命令；仍缺 AI、superscript/subscript、indent/outdent、完整 link popover 和 image floating toolbar |
| E16 | PARTIAL | 颜色与节点样式统一能力包 | 参考 `ColorMenu`、`color-text-button`、`color-highlight-button`、`node-background-extension.ts`；本地 toolbar 文字色走 `set_color`，背景色走 `set_highlight`，清除颜色走 `unset_color` + `unset_highlight`；仍缺 node background bridge、recent colors、drag menu 颜色子菜单复用和 smoke 对 JSON/刷新恢复断言 |
| E17 | PARTIAL | Link / Page / Reference 能力包 | 参考 link popover 与 `leptos-tiptap` `set_link/toggle_link`；已完成 `转换为 -> 页面` 真源和页面树可见，仍需补选中文字 `Ctrl/Cmd+K`、直接粘贴 URL、页面引用、块引用、右侧引用预览 |
| E18 | TODO | Clipboard / Paste 能力包 | 参考 registry 的 clipboard/copy 相关按钮与 Tiptap paste 规则；覆盖文本选择、块选择、复制副本、匹配样式粘贴、跨块粘贴，smoke 验证真实 Tiptap JSON 和 mnote 保存链 |
| E19 | PARTIAL | Indent / ListNormalization 能力包 | 已完成列表项 `Tab` / `Shift+Tab` 真父子结构闭环：Tiptap JSON 嵌套列表、mnote 保存链 `childBlockIds` / legacy `children`、刷新恢复均由 `task144-e19-indent-list-smoke.js` 覆盖；后续补非列表块 indent-extension、list-normalization 边界和不允许缩进块类型 |
| E20 | PARTIAL | NodeAlignment / BlockLayout 能力包 | 已完成 `Ctrl/Cmd+Shift+U` 块布局虚线轮廓和块菜单 `文字居中` 的 Tiptap textAlign 保存链：快捷键后 `block-layout-outline`、块菜单入口、点击后视觉居中、保存请求、`/api/documents/content` 和刷新恢复由 `task145-e20-alignment-smoke.js` 覆盖；剩余 selection toolbar 是否有对齐入口、拖拽分栏预览与节点级对齐需继续拆小任务，不能标 DONE |
| E21 | PARTIAL | TurnInto 转换能力包 | 参考 TurnInto 菜单模型；当前 `文本/待办/高级待办/H1-H4/页面/列表/数字列表/引述/代码` 基础入口部分完成，页面转换已接真实子页面；页面块与 H4 小标题二次打开 `转换为` 已有 `✓` 当前态 smoke，slash `zhw` 已能显示 `转换为 /zhw`，slash `ym` 已能显示 `页面 /ym`，基础快捷键 `Ctrl/Cmd+Shift+1/2/3/5/6/7` 已接本地 Tiptap 转换命令；后续补其余类型全量当前态与 Wolai 二次勾选态基线 |
| E22 | PARTIAL | Folding Blocks 能力包 | 已完成 `转换为 -> 折叠标题 -> 折叠主标题` 最小真源闭环：三级菜单、heading collapsed attr、保存请求、content API 和刷新恢复由 `task150-e22-folding-blocks-smoke.js` 覆盖；后续补折叠大/中/小标题 smoke、折叠待办/折叠列表真实语义、折叠后的子块显隐与当前态 |
| E23 | PARTIAL | TableKit 能力包 | 已完成简单表格可验收切片：`leptos-tiptap` 增加 table/tableRow/tableCell/tableHeader schema，slash `简单表格 /jdbg` 按 Wolai 基线插入 `4x3` 真实 `<table>`，本地 table toolbar 支持下方插入行、右侧插入列、清空当前单元格、删除当前行/列/表格，并补 `选项` 菜单的标题行、标题列、隐藏边框线 switch；已补行侧/列顶 aux controls 和最小 TableSelectionOverlay，点击行/列 aux 会插入行/列并显示对应淡红选择覆盖层，toolbar 保持可用；`core-protocol`/`bridge-runtime`/`mnote-web` 保存与刷新恢复保留 `table` Tiptap 快照、`tableHeader` 和 `attrs.hiddenBorders`；本地 smoke `task151-e23-table-smoke.js` 覆盖入口、DOM、row/column aux 插入、selection overlay、列宽拖拽、switch 语义/状态、保存请求、content API、reload 和删除。剩余表格对齐、fit、数据表格入口，以及 Wolai 选项菜单图标/toolbar 视觉细节另拆后续 |
| E24 | PARTIAL | Image / Media 能力包 | 已完成图片 `/tp` 最小真源闭环与图片 toolbar 小闭环：slash `媒体与附件` 分组入口调用 `leptos-tiptap` 官方 `set_image(TiptapImageResource)`，启用 `TiptapExtension::Image`，保存链新增 `EditorBlockType::Image` / `TiptapNode::Image` 并保留 `props.tiptapImage`，`mnote-web` reload 恢复 `<img>`；点击图片后出现 `image-floating-toolbar`，删除入口本切片保持禁用，左/中/右对齐通过官方 Image 扩展 `addAttributes("data-align")` + `updateAttributes("image")` 持久化，同源下载通过隐藏 `<a download>` 触发且不改文档；`task152-e24-image-smoke.js` 覆盖入口、实际图片加载、toolbar、同源下载、删除入口禁用态、居中对齐、保存请求、content API 和刷新恢复；剩余上传、最近上传、caption、resize、replace、跨源下载 fallback、删除保存链、移动端 toolbar、失败态 |
| E25 | PARTIAL | TOC 能力包 | 已完成 `/toc` 最小真源闭环：`leptos-tiptap` 新增真实 `tocNode` schema/command，slash `页面目录 /toc` 插入真实节点，NodeView 从当前 headings 派生目录项，支持点击定位、标题显示开关、保存请求、content API 与 reload 恢复；`task153-e25-toc-smoke.js` 覆盖入口、动态 heading 更新、hash 定位和 `props.tiptapTocNode`。剩余 TOC sidebar、active heading 高亮、完整块菜单入口、官方 TableOfContents v3 数据源评估、移动端与像素级视觉 |
| E26 | PARTIAL | UniqueID / Anchor 能力包 | 已完成最小真源闭环：Rust `EditorBlock.block_id` -> Tiptap `attrs.blockId` -> DOM `data-block-id` + `id` -> 复制链接 hash -> `page.body.save` / `/api/documents/content` -> reload 后 `:target` 定位；`task154-e26-anchor-smoke.js` 覆盖保存、复制、reload/hash 和截图。Tiptap `UniqueID` 仍只作为参考/辅助口径，不作为正式块 id；剩余更多块类型 anchor 覆盖、Wolai 视觉细节、引用预览和移动端行为。 |
| E27 | PARTIAL | AI 编辑能力包 | 已完成历史块菜单 `AI 助理` 主路径与最小写入闭环：点击后曾发起 `/api/ai-agent/run`，payload 使用 `scope=document`、`stream=true`、`options.ai.provider=online`，携带 `documentId`、`workspaceId`、Rust `blockId`、selection、selected text、Tiptap 快照和 `action=ask_ai`；`task155-e27-ai-edit-smoke.js` 与 `task156-e27-ai-writeback-smoke.js` 已默认退役为 historical smoke，当前只保留显式环境变量下的历史对照。2026-05-14 起页面 AI 主链已调用 Hermes client proxy；2026-05-22 起产品层运行态索引、权限和审计默认落 SQLite control-plane，Hermes/Reasonix runtime 的内部 session/message/tool event/usage/model 不等同于 MNote 产品层会话真相；mnote 通过 Hermes skill/plugin 执行 `page.body.save`、标题、页面设置、artifact、edge 等业务工具；`mnote-cli` 仅可作为 plugin 内部适配器。Auth 验收必须复用当前 SQLite control-plane 测试账号，真实 session / actor 优先，`dev identity` 仅为本地 fallback；Convex Auth 只作为历史 compat / cloud source 对照。剩余 slash AI/selection toolbar AI、Improve/continue/regenerate/summarize/translate、Wolai 视觉基线、`doc_insert_blocks` 多块插入与标题写入等细分入口。 |

2026-05-14 追加说明：E27 行中的 “Hermes client proxy 接入、mnote plugin tool 注册” 已由 `design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md` 对应的 7-5 / 7-6 合同和 mnote-web 实现推进到 GREEN：页面 AI 主链已走 Hermes session/run/events，mnote tool surface 已覆盖 `mnote.page.get`、`mnote.page.save`、`mnote.page.update_title`、`mnote.page.update_options`、`mnote.artifact.create_summary`、`mnote.artifact.create_ai_note`，旧 `/api/ai-agent/run` 已改为 `legacy_ai_agent_run_retired` guard。本文件后续只保留 Wolai-aline 体验、slash/selection toolbar AI 子命令和视觉/交互对标；页面 AI 长期主链完成状态以 `7-4` 为准。
| E28 | PAUSED | Mention / Emoji 能力包 | 2026-05-03 暂停；Wolai baseline 已纠偏：正文 `@` 当前是提醒/会议/成员候选入口，不是页面引用搜索，恢复时先重定 mention/emoji 口径，再决定 Tiptap JSON 与 mnote 保存链 |
| E29 | PAUSED | Comment / History 能力包 | 2026-05-03 暂停；评论/历史入口仍需后端边界和 Wolai 基线复核，待 E30 统一菜单状态机后再接入，避免继续复制独立弹层逻辑 |
| E30 | PARTIAL | Menu / Floating 状态机能力包 | 2026-05-03 第一刀已完成本地统一状态机 smoke：`task158` 覆盖 slash、块菜单/二级菜单、selection toolbar/color panel、image floating toolbar、table toolbar/options 的互斥打开、Esc 统一关闭、方向键 active，以及打开块菜单时关闭 image toolbar；Wolai 只读基线已确认 selection/type menu 和 table popper 的 Esc/外部点击/URL 不变，slash 与块菜单二级菜单在只读条件下不稳定，后续仍需 editable-test 复核 Enter、外部点击和更多层级收起 |
| E31 | PARTIAL | Tiptap 参考对标 smoke 矩阵 | `task137-wolai-phase-e-smoke.js` 已覆盖 E13 分割线的 DOM `<hr>`、`/api/documents/content` `divider`、刷新恢复和页面转换 `_self` 打开；后续每完成一个能力包仍必须同时断言 Tiptap JSON/schema、mnote 真源保存、Wolai 视觉/交互截图、刷新恢复；截图差异未复核不得标 DONE |

## 9. Phase F：Page Aggregate 和命令边界


| ID | 状态 | 任务 | 验收要点 |
| --- | --- | --- | --- |
| F1 | TODO | 标题单一真源 | 标题修改后 breadcrumb、sidebar、file tree、document title 同步 |
| F2 | TODO | 正文保存命令 | 编辑器保存继续走 `page.body.save`，不把 Tiptap 临时 id 当持久真相 |
| F3 | TODO | 页面设置语义 | 设置项进入 `page-option-semantics` 和 editor runtime，不做只保存不消费的假功能 |
| F4 | TODO | 页面树命令 | 新建、重命名、移动、归档仍沿 `tree.*`；菜单入口不直接操作本地临时数组 |
| F5 | TODO | 引用语义 | 页面引用、块引用、嵌入引用先保留类型边界，不降级成普通 URL |

## 10. 每轮收尾

每完成一个 ID，必须补齐：

- Wolai 截图路径：`TODO`
- 本地截图路径：`TODO`
- smoke / 测试命令：`TODO`
- 主线程复核结论：`TODO`
- 剩余差异：`TODO`

如果出现新的可复用失败模式，同步更新 `/home/lix/.codex/skills/wolai-aline/references/failure-patterns.md`。
