# 5-4 [process] `leptos-tiptap` 主编辑器纠偏与落地方案 v1

> 更新时间：2026-04-29
>
> 关联文档：
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/5-editor-baseline-reset-v2.md`
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/5-1-main-editor-cutover-entry-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-2-tiptap-notion-like-template-adoption-v1.md`
> - `/mnt/Data1T/mnote/design/old/05-editor-mainline/process/5-3-tiptap-leptos-rust-migration-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`

## 1. 文档目的

这份文档只解决一个已经开始偏掉的问题：

> **当 `mnote` 已经采用 `Tiptap + leptos-tiptap` 作为默认主编辑器输入 runtime 时，如何避免把剩余过渡适配层误当成“Rust + Leptos 主线已经完全成立”。**

当前需要纠偏的不是：

- 是否继续使用 `Tiptap`
- 是否继续使用 `leptos-tiptap`
- 是否继续让 Rust 掌握 editor truth

当前真正需要纠偏的是：

- **哪些改动已经把“过渡接法”抬成了主链**
- **哪些底层工作虽然还不完整，但应当保留**
- **后续应该按什么顺序推进，才能真正体现 Rust + Leptos 的长期优势**

---

## 2. 先给结论

结论固定为五句：

### 2.1 方向本身没有错

`Tiptap + leptos-tiptap + Rust truth` 仍然是当前最现实的主路线。

原因很简单：

- `Tiptap` 仍然是当前最成熟的浏览器富文本/块编辑 runtime 体系
- `leptos-tiptap` 已经提供了可在 Leptos 中稳定挂载、读写内容、触发命令、订阅变更的正式接缝
- `mnote` 当前没有更成熟的 Rust-native 输入层，可以在短期内替代 `Tiptap` 级的 selection / IME / history / slash / toolbar / handle 行为

因此：

> **当前不应放弃 `leptos-tiptap`，也不应回到“重新造一个 Rust 版 Tiptap”作为当前主交付。**

### 2.2 当前偏差也已经很明确

当前需要继续纠偏的主要偏差不是“换成了 `leptos-tiptap`”，而是：

- 默认文档页主链虽然已经切到页面内 `leptos-tiptap` island
  - `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`
  - `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/editor-host.tsx`
- 但仍保留 TS converter、fallback host、兼容保存链与部分 host/runtime 过渡层
  - `/mnt/Data1T/mnote/wolai-frontend/src/lib/documents/tiptap-content-converter.ts`
  - `/mnt/Data1T/mnote/recycle/wolai-frontend/src/components/editor/blocknote-editor.tsx`

这条线的问题不是“代码不能运行”，而是：

> **它虽然已经是页面内主编辑器，但剩余 fallback / adapter / 兼容保存链还没有完全退到过渡边界。**

### 2.3 当前最该回退的不是 Tiptap，而是默认主链切换方式

当前最该继续收口的是：

- **把 TS converter 继续降级为过渡适配层**
- **把 fallback host / 兼容保存链继续收回到非主路径**
- **让默认 `leptos-tiptap` 主链更多直接消费 Rust-first projection / command 边界**

当前不该回退的是：

- `core-protocol` 中新增的 `EditorBlockDocument <-> Tiptap` 桥接模型
- `leptos-tiptap spike` 中已经完成的实际交互 surface
- 官方模板行为模型对 `slash / floating toolbar / drag handle / turn into` 的约束

### 2.4 真正要体现 Rust + Leptos 优势，必须把主目标改写成下面这句话

> **让 `Tiptap/leptos-tiptap` 只负责 live editing surface；让 Rust 持有块真相、保存合同、命令合同、AI 合同；让 Leptos 成为正式页面内编辑 island，而不是额外 `iframe runtime`。**

### 2.5 AI 入口不能继续挂在浏览器壳边上

如果长期目标是：

- AI 直接进入主编辑区编写
- 人类只负责审核和辅助编辑

那么 AI 不能继续以：

- 直接拼 HTML
- 直接拼 Tiptap JSON
- 直接驱动前端壳层临时桥接逻辑

作为正式路径。

长期正确路径应固定为：

> **AI / CLI / 自动化先操作 Rust `EditorCommand` 与 `EditorBlockDocument`，编辑器 surface 只消费 Rust truth 的变更投影。**

---

## 3. 当前问题的具体判断

## 3.1 当前实现为什么没有体现 Rust + Leptos 的优势

从当前未提交改动看，问题集中在四个点。

### 3.1.1 文档页已经提前默认切流

当前：

- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx`

已把编辑态默认入口从 `BlockNoteEditor` 切到了：

- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/editor-host.tsx`

这意味着当前不是“有一个新 host 在旁路验证”，而是“主链已经被切了”。

### 3.1.2 host 仍然是 iframe runtime，不是 Leptos 主编辑 island

当前：

- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/leptos-tiptap-editor-host.tsx`

的真实结构是：

`DocumentContent`
-> `EditorHost`
-> `iframe`
-> `http://localhost:8123/?embedded=1`
-> `postMessage`
-> host 接收 `ready/change/save-request`
-> 前端转换后调 `/api/documents/save`

这条链的问题在于：

- 编辑器实例不在真实页面树内
- 父子之间不是同一运行时对象图
- `undo / redo / selection / current block id / reference insert` 仍是最小占位
- AI 面板与主编辑器之间无法共享一份真正稳定的 live editor handle

也就是说：

> **现在更像“Next 把一个外部 editor runtime 嵌了进来”，而不是“Leptos editor 成为页面内正式 island”。**

### 3.1.3 当前保存边界仍然由前端壳层掌控

当前：

- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/leptos-tiptap-editor-host.tsx`
- `/mnt/Data1T/mnote/wolai-frontend/src/lib/documents/tiptap-content-converter.ts`

承担了下面这些职责：

- Tiptap doc -> blocks
- blocks -> Tiptap doc
- save payload 组装
- stats 计算
- revision / conflict key 维护

这会造成一个长期问题：

> **Rust 还没有真正拥有唯一正式的 editor truth 边界，前端 host 仍然在定义一套过渡期格式语义。**

### 3.1.4 当前已经开始把“过渡默认值”写死

当前：

- `/mnt/Data1T/mnote/wolai-frontend/src/lib/runtime-config.ts`
- `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/editor-host-config.ts`

已经出现了把：

- `documentEditorHost`
- `EditorHostKind = "leptos_tiptap"`

提前写成固定默认值的趋势。

这会直接带来一个误判：

> **看起来像“主编辑器切流已完成”，实际上只是“默认把一条过渡桥接线抬上来了”。**

---

## 4. 当前哪些需要回退，哪些应保留

下面只针对“主编辑器纠偏”相关改动判断，不涉及与本任务无关的其它脏改动。

## 4.1 需要立即回退或降级的部分

| 范围 | 文件 | 动作 | 原因 |
| --- | --- | --- | --- |
| 主编辑器默认切流 | `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx` | 回退到“默认仍由现有正式可写链路承载”，`EditorHost` 不再直接替代默认主编辑器 | 当前接法仍是过渡 host，不是正式 Rust + Leptos 主链 |
| host 默认绑定 | `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/editor-host.tsx` | 降级为实验入口，不再代表默认 editor host | 当前只返回 `LeptosTiptapEditorHost`，会掩盖“还没完成正式切流”的事实 |
| iframe runtime 主链承载 | `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/leptos-tiptap-editor-host.tsx` | 降级为 `debug/prototype bridge`，不再作为默认主文档页保存链路 | 它是跨 iframe bridge，不是长期正式 island 形态 |
| 编辑页强行自动进入编辑 | `/mnt/Data1T/mnote/wolai-frontend/src/app/(app)/documents/[id]/page.tsx` | 回退 `edit=1 -> autoEnterEdit` 作为默认主链推进手段 | 当前真正问题不是“默认直接编辑”，而是“切入的是哪条编辑器链” |
| 运行时默认值写死 | `/mnt/Data1T/mnote/wolai-frontend/src/lib/runtime-config.ts` | 回退 `documentEditorHost` 这类提前写死的默认事实 | 当前 host 形态仍在纠偏，不能先把默认值冻结成产品事实 |
| host 配置空壳 | `/mnt/Data1T/mnote/wolai-frontend/src/components/editor/editor-host-config.ts` | 降级为后续使用的配置草稿，不作为当前切流依据 | 现在只有单值返回，没有真实 host 策略价值 |
| TS converter 生产化倾向 | `/mnt/Data1T/mnote/wolai-frontend/src/lib/documents/tiptap-content-converter.ts` | 从“正式保存边界”降级为“过渡适配器 / 测试夹具” | 不能让前端继续持有 editor truth 的唯一转换权 |

### 4.1.1 对“回退”的精确定义

这里的“回退”不是删除所有相关代码，而是：

1. **回退它们在主文档页中的默认地位**
2. **回退它们在正式保存链路中的事实地位**
3. **回退它们对最终架构口径的误导**

也就是说：

- 代码可以暂时保留
- 但必须从“默认主链”退回“实验/过渡/对照用途”

## 4.2 应明确保留的部分

| 范围 | 文件 | 动作 | 原因 |
| --- | --- | --- | --- |
| Rust Tiptap 协议桥 | `/mnt/Data1T/mnote/rust/crates/core-protocol/src/editor/tiptap.rs` | 保留并继续演进 | 这是 Rust 收口 editor truth 的必要桥层，不应因当前 host 方案错误而被否掉 |
| Rust Tiptap 导出入口 | `/mnt/Data1T/mnote/rust/crates/core-protocol/src/editor/mod.rs` | 保留 | 说明 Tiptap 映射已进入协议层，而不是停留在前端 |
| Rust 桥接测试 | `/mnt/Data1T/mnote/rust/crates/core-protocol/tests/editor_tiptap_bridge.rs` | 保留并扩充 | 这是正式语义边界回归的基础 |
| 8123 spike | `/mnt/Data1T/mnote/rust/spikes/leptos-tiptap-spike/src/main.rs` | 保留，但只作为 surface 行为样本和 embed 验证页 | 这里保存了最接近未来主编辑器的交互行为模型 |
| 官方模板行为参考 | `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/tiptap-notion-like-template/**` | 保留 | 它是体验 benchmark，不是迁移代码对象 |
| `leptos-tiptap` 参考库 | `/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/leptos-tiptap/**` | 保留 | 这是正式 Leptos 接入 runtime 的能力边界，不应再被降回 fallback |

### 4.2.1 对“保留”的精确定义

这些内容保留，不代表它们已经是最终主链。

它们保留的原因是：

- 已经证明方向是对的
- 已经沉淀了有价值的协议和行为模型
- 应该被吸收到正式主线，而不是被误伤回滚

---

## 5. 纠偏后的目标形态

纠偏后应固定下面四层边界。

## 5.1 Surface 层：`Tiptap + leptos-tiptap`

这一层只负责：

- 人类输入
- 光标与 selection
- slash / toolbar / handle / block menu
- 文本样式、块切换、拖拽等浏览器 runtime 行为

它不负责：

- 最终块真相
- 持久化格式真相
- AI 改写正式合同
- 页面树 / projection 真相

## 5.2 Truth 层：Rust `EditorBlockDocument`

这一层负责：

- 块身份 `block_id`
- 块结构与块类型
- 命令合同
- 保存合同
- AI/CLI 共享的编辑真相

这里必须固定一句：

> **`Tiptap JSON` 不是长期事实源，Rust `EditorBlockDocument` 才是。**

## 5.3 Orchestration 层：Rust command / save / AI contract

这一层负责：

- `EditorCommand`
- AI 生成与改写
- 保存与冲突检测
- 审计、trace、历史
- 对外导入导出合同

也就是说：

> **AI 的正式入口必须先进入 Rust 命令层，而不是直接进入浏览器编辑器 JSON。**

## 5.4 Host 层：Leptos island，而不是长期 iframe

长期正式形态必须是：

- 主编辑区作为页面内正式 editor island
- 与真实页面共享同一交互壳和状态上下文
- 能被 AI 面板、侧栏、评论、引用面板通过正式接口驱动

长期不应固定成：

- `iframe + postMessage + save-request`

因为那只适合作为：

- 迁移期桥接
- 单独验收
- embed 验证

不适合作为长期主编辑区的正式形态。

---

## 6. 纠偏后的落地顺序

后续推进建议分五段，不再平均推进所有功能。

## 6.1 Phase A：主链降温与事实回正

目标：

- 把当前过渡 host 从默认主链降回实验地位
- 恢复“还未正式切流完成”的事实口径

清单：

- [x] 回退 `DocumentContent` 中直接以 `EditorHost` 替换默认主编辑器的改动
- [x] 回退 `runtime-config.ts` 中把 `documentEditorHost` 提前写死成事实默认值的改动
- [x] 回退 `page.tsx` 中把 `edit=1` 当成主推进抓手的做法
- [x] 明确 `EditorHost`、`LeptosTiptapEditorHost` 当前只作为 `debug/prototype bridge`
- [x] 保留 spike、保留 Rust Tiptap bridge、保留测试

退出标准：

- 默认文档页不再假装“主编辑器已切流完成”
- 当前架构讨论重新回到真实状态

## 6.2 Phase B：Rust truth 单边界收口

目标：

- 停止让前端 host 掌握正式保存边界

清单：

- [x] 把 `EditorBlockDocument <-> Tiptap doc` 的正式边界收口到 Rust 协议层
- [ ] TS `tiptap-content-converter.ts` 降级为测试/过渡适配器，不再作为唯一正式保存边界
- [ ] 统一 `block_id` 口径：Rust 真相优先，`UniqueID` 仅作 runtime 辅助
- [x] 明确最小块型正式覆盖：`Paragraph`、`Heading`、`BulletListItem`、`NumberedListItem`、`Todo`、`Quote`、`CodeBlock`
- [ ] 明确 AI / CLI / 人类编辑共享同一套 `EditorCommand`

退出标准：

- 任一文档编辑变更都能回到 Rust `EditorBlockDocument`
- 前端不再拥有第二套长期 editor truth

## 6.3 Phase C：把编辑器本体迁到正式 Leptos island

目标：

- 把 `leptos-tiptap` 从“外部 runtime / bridge host”变成“正式页面内 Leptos island 本体”

清单：

- [x] 明确长期 host 不再以 `iframe + postMessage` 为主
- [x] 明确“正式 island”不等于 React 壳内调用 `bridge.create/document/command`；正式主链必须是 Leptos/WASM 编辑器本体挂到页面内指定容器
- [x] 设计正式的 Leptos editor mount 方式，使主编辑区与页面壳共享同一状态上下文
- [x] 把 `8123 spike` 从 `mount_to_body` 页面演示形态改成“可挂到指定 DOM 节点、可 mount/unmount 的 island 本体”
- [x] 把宿主与 island 的通信收敛成同页 typed 接口或自定义事件，而不是 `iframe` 消息协议
- [x] 让 `undo / redo / current block / selection / insert reference / replace content` 进入 island 内部真实接口
- [ ] 让 AI 面板与编辑区之间共享正式 editor handle 或等价命令入口

退出标准：

- 主编辑区已不再依赖跨窗口消息维持基本交互
- 主编辑区已不再依赖 React `runtime bridge` 作为长期控制面
- Leptos 编辑器本体真正进入主文档页主交互链

## 6.4 Phase D：正式 island 接入后的真实回归锁定

目标：

- 在 Rust truth 和正式 Leptos island 都成立之后，先把默认切流前必须锁定的真实回归做完整

清单：

- [x] 以真实 `/documents/[id]` 页面完成“正式 island”打开、编辑、保存、刷新回填回归
- [x] AI 改文档时先走 Rust `EditorCommand`
- [ ] 人类编辑与 AI 编辑都回到同一份块真相
- [x] `block menu / slash / toolbar / turn into / 引用插入 / undo / redo` 在真实页面中行为稳定
- [ ] 宿主只保留 mount/ref、初始化数据、最小回调与 editorBridge 出口，不再自己维护编辑器内部状态机
- [x] 补齐默认切流前的 smoke / rollback / 观测检查项

退出标准：

- 进入 Phase E 时，不再依赖主观判断说“应该可以切默认了”

## 6.5 Phase E：正式切换默认主编辑器为页面内 `leptos-tiptap` island

目标：

- 正式把默认主编辑器从 `BlockNote` 切到页面内 `leptos-tiptap` island
- 让 `BlockNote` 退出运行时主路径，只保留 `recycle/` 历史参考副本，而不是继续承担默认主链
- 让默认主链不再依赖 `iframe runtime` 或 React `bridge runtime`

清单：

- [x] 收敛正式 host 命名：`leptos_tiptap_runtime` 改为“正式 island host”语义，`leptos_tiptap_inline` 仅保留为兼容别名；历史 `leptos_tiptap_iframe_debug` 已退出文档页 host 选择面，仅剩源码参考实现
- [x] 修改 `DocumentContent`、`page.tsx`、`runtime-config.ts` 的默认分发逻辑，使不带任何参数的 `/documents/[id]` 直接进入正式 `leptos-tiptap` island 主链
- [x] 删除默认主链对 `loadLeptosTiptapRuntime()` / `bridge.create()` / `bridge.document()` / `bridge.command()` 这种 React 控制面的依赖
- [x] 历史 `blocknote` 显式回退链已退到 `recycle/`，不再作为当前 runtime config、query 参数或 feature flag 组成部分
- [x] 把 `BlockNoteEditor` 降为 `recycle/` 历史参考实现，不再继续承接新的长期 editor truth、save contract、AI contract 语义
- [x] 为默认切流补齐真实 smoke：打开、输入、撤销、重做、引用插入、AI 改写、保存、刷新回填、异常回退
- [x] 为默认切流补齐观测项：runtime 加载失败、hydration 失败、Rust command 失败、保存失败、自动回退次数
- [x] 先完成开发环境默认切流，再进入受控范围的真实使用默认切流；每一步都保留 kill switch
- [x] 更新设计稿、运行时注释与口径，明确“默认主编辑器已切到页面内 `leptos-tiptap` island，`BlockNote` 仅保留 `recycle/` 历史参考副本”

### 6.5.1 当前验证记录（2026-04-21，2026-04-29 复核）

- [x] `http://127.0.0.1:3000/documents/[id]` 在不带 `editorHost` 参数时默认进入页面内 `leptos_tiptap` island，而不是 `iframe` 或 React `bridge runtime`
- [x] 侧边栏“新建页面”不再依赖 `edit=1`；当前 3000 Rust Web 侧栏 `+` 会通过 `/api/tree/commands` 新建页面并直接进入默认 `leptos-tiptap` 主链，`task122` 已覆盖
- [x] `task108-document-default-editor-cutover-smoke.js` 已移入 `recycle/scripts/`，不再作为当前 3000 主链验收项
- [x] `editorHost=blocknote` 显式回退已退出当前 3000 Rust Web shell 的活跃验收范围；旧 Next/React fallback 只保留历史参考意义
- [x] `DocumentContent` 已暴露主链观测点：`runtime_load_failed`、`host_init_failed`、`command_failed`、`save_failed`、`fallback_count`
- [x] 已修正 island `embedded` 模式判定，不再因为缺少 `?embedded=1` 而把 spike 页面壳误渲染进 3000 正式文档页
- [x] 已移除正式主链中的 spike 开发态壳元素：`hero`、重复标题、开发态提示文案、调试抽屉不再出现在 `/documents/[id]` 默认视图
- [x] 已在真实浏览器验证：`slash` 菜单、选区浮动工具栏、空页首屏块手柄都能在 3000 默认主链中出现
- [x] 已在真实浏览器验证：默认 island 首屏不再刷 `Maximum update depth exceeded`，`change` 风暴已收敛，普通文本输入后可进入 `saved`，刷新后可回填
- [x] 已在真实浏览器验证：双文档 A/B 切换后各自内容不串页，刷新后按页回填；`/api/documents/save` 请求中的 `documentId/workspaceId` 已按当前页面正确绑定
- [x] 已修正正式主链中的本地草稿隔离：Rust island 不再使用全局单一 `localStorage` key，改为按 `workspaceId/documentId` 分桶
- [x] 已修正正式主链中的布局偏移：页面内 island 宿主不再额外施加横向 padding，编辑正文列、块手柄和 drop indicator 已回到同一几何基准
- [x] 已收敛切页期的 disposed signal 访问风险：窗口级 `mousemove/mouseup/keydown` listener 已改为 `try_get_untracked/try_set` 安全访问，避免在页面切换时继续触碰已释放 reactive value
- [x] `task108` 已随 `BlockNote` fallback 退场移入 `recycle/`；不再用 blocknote fallback 证明当前 3000 Rust shell 完成度
- [x] `task121` / `task122` 已覆盖当前 3000 默认 island 的 hydrate、输入、保存、reload 读回和 UI 新建页面进入主链
- [ ] 当前 `slash / floating toolbar / drag handle / turn into` 仍是 island 内部的最小自制实现，尚未对齐官方 notion-like 模板的组件层级、视觉细节与菜单能力

### 6.5.2 Phase E 硬约束

- 正式主链中的 `leptos-tiptap` 必须是页面内 Leptos island 本体，不接受 `iframe`、外部 runtime 页面壳或 React `bridge runtime` 作为“已完成”实现。
- `8123` 只允许作为能力参考、资产构建来源或调试入口；不允许继续把 `8123` 页面本身嵌进 3000 主文档页。
- 宿主只允许保留容器挂载、初始化数据、最小回调和兼容期 `editorBridge` 出口；`slash / toolbar / block menu / selection / top-level mutation` 必须回到 island 内部。

退出标准：

- 不带参数的 `/documents/[id]` 默认进入 `leptos-tiptap`
- 出现问题时优先修正式 `leptos-tiptap` 主链，不再把回退到 `BlockNote` 作为默认策略
- 默认链路下的 Rust truth、AI contract、save contract 保持不变
- `BlockNote` 不再是默认主编辑器，也不再是当前运行时保险丝；仅保留 `recycle/` 参考副本

---

## 7. 当前阶段明确不做什么

为了避免再次跑偏，下面这些项当前不进入前排：

- 不继续围绕 `runtime shell` 做 polish
- 不把 `iframe host` 继续包装成“正式页面”
- 不先做图片上传整链
- 不先做表格
- 不先做协作
- 不先接 Tiptap Cloud AI
- 不先做一轮大规模 Wolai 对标 UI 细节打磨
- 不回到“自研 Rust-native 输入层”作为当前主交付

这些项并非永久放弃，而是：

> **它们都不该排在“纠正主链边界错误”之前。**

---

## 8. 对 AI-first 目标的直接收口

如果 `mnote` 的长期预期是：

- AI 直接在主编辑区编写
- 人类只做审核和辅助编辑

那么后续必须固定下面这条规则：

1. AI 正式入口只走 Rust `EditorCommand`。
2. `EditorBlockDocument` 是 AI、人类、CLI 的共享真相。
3. `Tiptap/leptos-tiptap` 只负责把这份真相投影成可编辑 surface。
4. AI 不直接成为 HTML/Tiptap JSON 拼接器。

这条规则的意义在于：

- 不把系统命运绑定到某个浏览器编辑器格式
- 为未来替换 surface 保留空间
- 保持 Rust 语义主导权

---

## 9. 最终结论

这轮 `leptos-tiptap` 集成真正的问题，不是路线选错，而是：

> **把一条过渡桥接线过早抬成了默认主链，导致 `Tiptap` 看起来像在主导系统，而 Rust + Leptos 还没有真正主导页面内编辑、保存合同和 AI 合同。**

因此这份纠偏文档固定如下结论：

1. `Tiptap + leptos-tiptap` 继续保留为主路线，不回到“自研 Rust 版 Tiptap”。
2. 当前需要回退的不是 `Tiptap` 本身，而是默认主链中 `iframe host + TS converter + 旧 save path` 的提前切流。
3. 当前需要保留的是 Rust `EditorBlockDocument <-> Tiptap` 桥层、测试和 spike 中已经成立的 surface 行为。
4. 下一步不是继续 polish runtime shell，而是先把 editor truth、save contract、AI contract 收回 Rust，再把 `leptos-tiptap` 做成正式 Leptos island。
5. 只有在这之后，`leptos-tiptap` 才能真正体现 Rust + Leptos 架构的优势，而不是继续表现成一个被宿主页面嵌入的外来编辑器。
