# [recycle] mnote 从 Runtime 壳回到 Wolai 目标页的纠偏清单 v1

> 更新时间：2026-04-18
>
> 最终交付对标基准：
> - 本地目标截图：`/mnt/Data1T/mnote/tmp/image copy 14.png`
> - 目标页面：`https://www.wolai.com/liaibo/ikFSSM1a4GgvmHBYFCNfVd`
> - 当前偏移截图：`/mnt/Data1T/mnote/tmp/image copy 13.png`
>
> 说明：
> - `dokobot` 当前只能稳定读到 Wolai 的 SPA 外壳标题，拿不到正文结构。
> - 因此本文以本地目标截图 `image copy 14.png` 作为最终视觉与交互验收基准。

## 1. 这份文档解决什么问题

当前代码和阶段文档虽然把“最小可写 runtime 闭环”做通了，但实际交付物仍然是一个：

- `iframe` 挂载的独立文档壳
- 带 `Document Editor Shell` 标题的调试页
- 带 revision/save/focus/selection/hover/event log 的 runtime 面板
- 基于 `textarea + 按钮工具条 + 块卡片` 的工程壳

它和目标页的差距，不是“差一点样式”，而是：

- 页面架构不对
- 交互壳不对
- 验收标准不对
- 默认主路径不对

本文的目的，是把后续交付标准重新冻结为：

> **最终默认交付必须逼近 `image copy 14.png` 这种一体化 Wolai 页面，而不是继续优化 `image copy 13.png` 这类 runtime 调试壳。**

---

## 2. 最终交付标准

最终默认交付以目标截图为准，至少必须满足下面这些显性特征。

### 2.1 页面结构标准

- 左侧是产品级导航树，而不是单独文档调试页。
- 中间是文档页面本身，不通过 `iframe` 二次嵌套。
- 顶部是轻量面包屑 / 导航动作，不出现 runtime 诊断信息。
- 正文区域是沉浸式页面画布，不出现工程面板、状态卡、调试日志。
- 右上角是产品动作区，不是编辑器内部调试控件区。

### 2.2 编辑体验标准

- 页面标题是正文的一部分，视觉上属于页面内容，而不是壳标题。
- 首块内容直接以内联块形态出现，不是“卡片块列表 + badge + tag”。
- 占位文案应以内联方式出现在正文里，例如“输入 `/` 选择，按 `空格` 打开 AI...”，而不是单独的控制台提示区。
- 勾选框、标题、段落、列表在正文中应呈现为自然文档流，不应被包成工程卡片。
- slash、引用、缩进、折叠等交互应在光标附近或块上下文中触发，不依赖页顶按钮排布。

### 2.3 禁止出现的元素

默认交付页中禁止出现：

- `Document Editor Shell`
- `revision=`
- `updatedAt=`
- `save=`
- `focus=`
- `selection=`
- `hover=`
- `交互状态`
- `最小状态机`
- `最近事件`
- `block_editor_shell.ready`
- 页顶固定一排 `Slash 菜单 / 折叠标题 / 缩进 / [[page]] / ((block))` 按钮
- `Paragraph / Heading / Todo` 这种脱离光标上下文的演示按钮

---

## 3. 当前偏移的根因

### 3.1 默认主路径被切成了 `iframe` 文档壳

当前默认文档页在命中文档壳开关后，直接返回 `MnoteWebDocumentShellHost`，并在其中挂一个 `iframe`。

相关代码：

- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx:183`
- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/mnote-web-document-shell-host.tsx:39`

这一步本身就决定了它不会长成目标截图那种“一体化页面”。

### 3.2 当前 `/document` 路由本质是 runtime 调试页

当前 Rust 文档页直接输出了：

- `Document Editor Shell`
- hero 说明
- meta pills
- status card
- toolbar buttons
- interaction sidebar
- event log

相关代码：

- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:790`
- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:805`
- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:821`
- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:838`

这不是“产品 UI 还没 polish”，而是“页面职责定义错了”。

### 3.3 当前块渲染是工程卡片流，不是正文文档流

当前每个 block 是：

- `li.editor-row`
- 左侧 badge
- 中间 title/meta
- 下方 `textarea`
- 右侧 state tag

相关代码：

- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:1408`
- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:1420`
- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:1426`
- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs:1437`

这类结构适合调试事务，不适合对标 Wolai 页面。

### 3.4 验收标准被收缩成“最小可写闭环”

当前 smoke / harness 的判断标准主要是：

- 文档页里出现 `iframe`
- `iframe` 里出现 `Document Editor Shell`
- 能找到 `textarea[data-block-input-id]`
- 能点击页顶 slash 按钮
- 能看到 event log 标记

相关脚本：

- `/mnt/Data1T/mnote/recycle/scripts/task103-document-shell-cutover-smoke.js:17`
- `/mnt/Data1T/mnote/recycle/scripts/task103-document-shell-cutover-smoke.js:25`
- `/mnt/Data1T/mnote/recycle/scripts/task104-document-runtime-input-smoke.js:29`
- `/mnt/Data1T/mnote/recycle/scripts/task104-document-runtime-input-smoke.js:46`
- `/mnt/Data1T/mnote/recycle/scripts/task106-document-runtime-slash-reference-smoke.js:34`

相关任务口径：

- `/mnt/Data1T/mnote/harness-tasks.json:2124`
- `/mnt/Data1T/mnote/harness-tasks.json:2248`
- `/mnt/Data1T/mnote/harness-progress.txt:193`
- `/mnt/Data1T/mnote/harness-progress.txt:203`

所以代码确实“通过了验收”，但那个验收根本不是目标页验收。

### 3.5 文档策略与产品目标之间出现了中途收缩

当前主基线文档明确收口到：

- AI-first
- CLI-first
- Rust-native
- 轻量块编辑
- 最小可写闭环

相关文档：

- `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/ai-first-rust-block-editor-baseline-v1.md:19`
- `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/ai-first-rust-block-editor-baseline-v1.md:105`

这条路线适合先打通内核，但不能直接当作“产品默认完成态”。

---

## 4. 纠偏总原则

后续纠偏必须遵循下面四条。

### 4.1 默认交付优先级重排

优先级改为：

1. 默认页面必须像目标截图那样是一体化产品页
2. 编辑交互必须内嵌在页面内容流中
3. Rust command / save chain / projection 继续保留
4. runtime 调试信息只能退到 debug 模式

不能再把“Rust runtime 闭环”放在默认页面形态之上。

### 4.2 `/document` 壳降级为 debug / prototype

`mnote-web /document` 可以保留，但只能作为：

- `?editor=runtime-debug`
- `?editor=prototype`
- 内部调试壳
- transaction / IME / save chain 诊断页

它不能再是默认主编辑器。

### 4.3 `iframe` 方案退出默认主链

默认文档页必须回到页面内原生渲染：

- 不再通过 `iframe` 承载默认编辑器
- 不再让页面主体验依赖另一个独立 HTML 文档
- 不再让产品页布局与编辑器页布局分裂

### 4.4 调试能力后移，不再前置

这些能力应该保留，但只能后移到 debug：

- focus / selection / hover
- event log
- revision / updatedAt / save status
- runtime 状态机说明
- editor command buttons

---

## 5. 必须立即执行的纠偏项

下面这些项不是“优化建议”，而是必须执行的逆转动作。

### 5.1 默认主路径逆转

- [ ] 把默认文档页从 `MnoteWebDocumentShellHost` 切回页面内主渲染路径。
- [ ] `page.tsx` 中默认逻辑不得再优先返回 `iframe` 壳。
- [ ] `mnoteWebDocumentShellEnabled` 只能控制实验入口，不能控制默认编辑器。
- [ ] `?editor=compat` 保留，但新增 `?editor=runtime-debug`，明确实验壳用途。

涉及文件：

- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/mnote-web-document-shell-host.tsx`

### 5.2 `/document` runtime 页角色重命名

- [ ] 把 `Document Editor Shell` 明确改名为 `Runtime Debug Shell` 或等价名称。
- [ ] 页面文案必须承认它是 debug/prototype，而不是默认编辑器。
- [ ] 该页默认不再通过主文档页直达。

涉及文件：

- `/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/editor.rs`

### 5.3 删除默认页面中的调试区块

默认产品页必须移除：

- [ ] hero 说明区
- [ ] meta pills
- [ ] status card
- [ ] interaction sidebar
- [ ] event log
- [ ] 页面顶部固定命令按钮

注意：

- 调试区块可以迁到 `debug panel`
- 但不能继续留在默认编辑页 DOM 里

### 5.4 页面内编辑器替换卡片流

- [ ] 块渲染必须退出 `li + badge + meta + textarea + state-tag` 这种工程卡片结构。
- [ ] 默认正文必须改成自然文档流：
  - 标题就是标题
  - 勾选就是勾选
  - 段落就是段落
  - 列表就是列表
- [ ] 块级信息如 `depth=0 / editable=true / type:paragraph` 只能进入 debug，不得出现在正文。
- [ ] 正文留白、字号、宽度、块间距必须向目标截图靠拢。

---

## 6. 分阶段纠偏清单

## 阶段 A：先把默认主路径拉回产品页

### 目标

先解决“默认打开文档时为什么像独立调试站点”。

### Checklist

- [ ] 默认文档页退出 `iframe` 模式。
- [ ] 页面回到 `DocumentShell -> DocumentContent` 一体化主链。
- [ ] 保留 runtime 壳，但只允许通过显式 debug 参数进入。
- [ ] 主路径不再展示 `Document Editor Shell` 文案。
- [ ] 主路径不再依赖 `mnote-web-document-shell-host.tsx`。
- [ ] 补回归：
  - 默认文档页 DOM 中不再存在 `iframe[title^="mnote-web-document-shell"]`
  - `editor=runtime-debug` 时才允许出现 iframe 或独立壳

### 完成判定

- 用户打开页面时，首先看到的是产品页，而不是 runtime 站点。

## 阶段 B：恢复 Wolai 式页面骨架

### 目标

把“产品页壳”恢复到目标截图的感觉。

### Checklist

- [ ] 左侧继续复用现有页面树/导航系统，不为编辑器单独造站。
- [ ] 顶部保留产品导航：
  - 面包屑
  - 返回/前进
  - 右上角产品动作
- [ ] 页面标题回到正文主列内部，而不是 debug 页标题。
- [ ] 正文宽度、留白、顶部间距对齐目标截图。
- [ ] 页面空白区域保留沉浸式阅读/编辑氛围，不塞调试信息。
- [ ] 若现有 compat 页骨架更接近目标截图，优先复用它的产品壳，而不是继续美化 runtime 壳。

### 完成判定

- 不看功能，只看静态截图，页面也应该更像 Wolai 页面而不是内部工具页。

## 阶段 C：把编辑器从“卡片列表”改成“正文文档流”

### 目标

解决当前最刺眼的视觉偏移。

### Checklist

- [ ] 去掉块左侧 badge 序号。
- [ ] 去掉块右侧 `block:id / type:xxx` 标签。
- [ ] 去掉每块上方 `Paragraph / depth=0 / editable=true` 元信息。
- [ ] 标题块渲染为正文中的标题，不再单独加工程 title 行。
- [ ] todo 块渲染为真实勾选项。
- [ ] `textarea` 若继续保留，只能作为无边框、无卡片感的内联输入宿主。
- [ ] 若 `textarea` 无法支撑自然正文体验，则必须把 `kode` 真正接入“块内输入器”层，而不是只停留在文档参考。
- [ ] `[[page]]` / `((block))` 的插入入口改成光标附近上下文，不再只靠页顶按钮。
- [ ] slash 菜单改为光标上下文菜单。

### 完成判定

- 用户看到正文时，应先感知“文档内容”，而不是“块调试单元”。

## 阶段 D：把交互从“页顶按钮”改成“块内上下文”

### 目标

解决当前交互方式明显不像 Wolai 的问题。

### Checklist

- [ ] 去掉页顶固定 `Slash 菜单 / 折叠标题 / 缩进 / [[page]] / ((block))` 按钮。
- [ ] slash 触发改为输入 `/`。
- [ ] 页面引用改为输入 `[[`。
- [ ] 块引用改为输入 `((` 或等价上下文入口。
- [ ] 缩进 / 反缩进改为 `Tab / Shift+Tab` 主触发。
- [ ] 标题折叠优先放在标题左侧 affordance，而不是页顶全局按钮。
- [ ] 块 hover 菜单应轻量化，只在块附近出现。
- [ ] 保留调试按钮，但移入 debug 模式或开发者工具抽屉。

### 完成判定

- 核心编辑动作不依赖页面级按钮栏。

## 阶段 E：调试能力彻底后移

### 目标

让默认产品页彻底脱离 runtime 调试感。

### Checklist

- [ ] `revision / save status / focus / selection / hover` 移到 debug 面板。
- [ ] `event log` 移到 debug 面板。
- [ ] `最小状态机` 文案移到 debug 面板。
- [ ] debug 面板默认关闭，只在显式调试开关下出现。
- [ ] 生产态 DOM 中不出现 `block_editor_shell.ready` 等字符串。

### 完成判定

- 默认页面截图不再暴露任何 runtime 术语。

## 阶段 F：验收标准重写

### 目标

防止再次出现“工程闭环通过了，但产品页仍然不对”的误判。

### Checklist

- [ ] 废弃以 `iframe + Document Editor Shell + textarea` 为成功条件的默认验收。
- [ ] 重写 `task103~107` 类 smoke 的默认成功条件。
- [ ] 新增产品级验收断言：
  - 默认文档页没有 `iframe[title^="mnote-web-document-shell"]`
  - 页面不存在 `Document Editor Shell`
  - 页面不存在 `交互状态`
  - 页面不存在 `最近事件`
  - 页面存在产品导航树
  - 页面标题在正文主列内
  - 第一块内容以内联块形式出现
  - 占位文案直接出现在正文中
  - slash 菜单由输入 `/` 触发
- [ ] 新增截图验收：
  - 至少保留一组默认页截图
  - 用于与目标截图做人工对照
- [ ] Final QA 的表述从“最小可写闭环”改为“产品级默认编辑页达到目标页标准”。

### 完成判定

- 测试通过时，默认页面也必须像目标页，而不是仅仅可写。

---

## 7. 参考层在这次纠偏中的正确用法

这次纠偏不是要推翻 Rust 内核，而是要纠正“参考层只停留在文档里，没有真正进入主路径”的问题。

### `edita-core`

继续用于：

- command 容器
- transform / transaction 思路

不用于：

- 默认产品页 UI

### `blocks`

继续用于：

- block model
- import/export
- history / diff / merge

不用于：

- 正文视觉与交互壳

### `kode`

这次必须优先重新评估它是否能真正承担：

- 块内输入器
- Markdown/WYSIWYG 内联编辑
- 光标附近上下文交互

如果 `textarea` 无法做出目标页的正文感，`kode` 不能再只停在“设计参考”。

### `leptos-tiptap`

继续作为 fallback：

- 当 `kode` 与自有块编排组合后仍无法提供足够自然的编辑体验时
- 用来验证 Leptos 对接成熟编辑 runtime 的现实成本

### `mnote-next`

只继续作为：

- 交互样例
- 历史反例

不再作为：

- 视觉或产品交付参考

---

## 8. 关于 “Tiptap 体验” 的补充判断

这一条必须单独说清。

### 8.1 仅执行本文前面的纠偏项，不足以自动获得 Tiptap 级体验

原因很直接：

- 前文主要纠正的是“默认页面壳”
- 纠正的是 `iframe`、调试面板、卡片块流、验收标准
- 这些动作可以让页面更像 Wolai
- 但它们不会自动提供 `Tiptap / ProseMirror` 那种输入体验内核

如果底层仍然是：

- `textarea` 作为主要输入宿主
- 自己拼 selection / composition / slash / token / hover 菜单
- 自己再把这些交互拼成正文体验

那么最终结果最多是：

- “更像 Wolai 的产品壳”
- “更自然的块 Markdown 编辑器”

而不是天然等于：

- “接近 Tiptap 的成熟输入体验”

### 8.2 如果最终目标明确是“类似 Tiptap 的体验”，应该把 `leptos-tiptap` 从 fallback 提升为重点实施分支

当下面这些诉求成立时，建议把 `leptos-tiptap` 提升为主候选，而不是继续只把它当 fallback：

- 你要的是接近 Wolai / Tiptap 的输入手感
- 你重视成熟 selection / composition / inline behavior
- 你希望 slash、placeholder、mark、node 行为更接近现成富文本编辑器
- 你不希望长期自己维护 `textarea + 自拼交互` 这条路

这时更合理的路线是：

1. 产品页壳按本文前半部分纠偏，先回到一体化页面
2. 人类编辑 surface 优先改成 `leptos-tiptap`
3. Rust kernel 继续保留为事实源、命令层、AI/CLI 层
4. 通过 adapter 把 `Tiptap JSON / command / selection event` 映射到 Rust block model / command

### 8.3 更准确的架构收口应该是“双层分工”，而不是二选一

如果采用 `leptos-tiptap`，建议分工固定为：

- `Tiptap / leptos-tiptap`
  - 负责人类交互体验
  - 负责 selection、composition、placeholder、toolbar/slash、inline behavior
- Rust editor core / kernel
  - 负责事实源
  - 负责命令合同
  - 负责 AI/CLI 共用写链
  - 负责导入导出、审计、projection、持久化

也就是说：

> **对“人类编辑体验”妥协给 `Tiptap`，不等于对“系统语义主导权”妥协给 `Tiptap`。**

### 8.4 什么时候不该上 `leptos-tiptap`

只有在下面这些条件同时成立时，才继续坚持纯 Rust-native 输入壳：

- 你接受第一版明显不像 Tiptap，只求最小可写
- 你接受更长时间去补 selection / IME / inline interaction
- 你把 Rust-native 纯度放在“像 Wolai/Tiptap 的体验”之前

而你当前这一轮明确表达的是：

> **你真正想要的是类似 Tiptap 的体验。**

在这个前提下，继续默认押注 `textarea + 自拼交互`，风险会非常高。

### 8.5 本文后的新增执行要求

基于上面的判断，后续纠偏不应只做“页面壳纠偏”，还应新增一个并行分支：

- [ ] 新增 `Tiptap 体验纠偏` 分支文档
- [ ] 用 `leptos-tiptap` 做一个真正的页面内 spike，而不是停留在 reference-code
- [ ] 对比三条路线：
  - `textarea + 自拼交互`
  - `kode` 块内输入器
  - `leptos-tiptap`
- [ ] 以“接近目标页体验”而不是“谁更 Rust-native”作为第一判断标准
- [ ] 若 `leptos-tiptap` 的 spike 明显更接近目标页，应把它提升为默认人类编辑 surface 方案

---

## 9. 最终一句话收口

后续默认交付口径固定为：

> **Rust editor core 可以继续最小化，但默认页面不能再像 runtime 调试站点；默认页面必须回到 Wolai 式一体化产品页，runtime 壳只保留为 debug/prototype。**

如果进一步收紧到“体验也要接近 Tiptap/Wolai”，那么还要再补一句：

> **页面壳纠偏只能解决“像不像产品页”，不能单独解决“像不像 Tiptap”；若目标是 Tiptap 级体验，应认真把 `leptos-tiptap` 提升为主候选，而不是继续只放在 fallback。**
