Files
mnote/design/old/04-tree-domain/process/4-9-tree-rust-family-cutover-remaining-architecture-and-capability-preservation-v1.md
T

16 KiB

4-9 [recycle] 树域 Rust 家族化剩余架构事项与能力保留方案 v1

更新时间:2026-04-23

回收说明(2026-04-28):本文是 Rust 家族化下一阶段的早期架构拆解稿,后续已由 4-10 执行清单、4-11 final renderer / host thinning、4-16 remaining final runtime、4-18 final DOM shell hard gate 继续拆分和覆盖。本文保留为历史能力保留口径,不再作为当前活跃 process 入口。

关联文档:

  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-sidebar-pagetree-filetree-rust-web-rebuild-v1.md
  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-2-sidebar-pagetree-filetree-product-interaction-contract-v1.md
  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md
  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-4-tree-projection-protocol-contract-v1.md
  • /mnt/Data1T/mnote/design/04-tree-domain/done/4-7-tree-shell-ui-state-boundary-v1.md
  • /mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md
  • /mnt/Data1T/mnote/design/03-rust-web/process/3-3-rust-web-tree-realtime-event-stream-v1.md
  • /mnt/Data1T/mnote/ARCHITECTURE.md

1. 文档目的

这份文档只回答两个问题:

  1. 在当前长期方向已经固定为 Rust kernel + Rust web + Leptos island + Convex substrate 的前提下,树域继续朝 Rust 家族化推进,还剩哪些真正的架构事项。
  2. page tree / file tree 从当前 TypeScript + Next + React 主壳向 Rust 家族执行面迁移时,哪些现有能力必须被完整保留,不能为了“换语言”而退化。

这份文档不是为了重复证明:

  • Convex 是否还保留
  • 树域是否已经具备 projection contract
  • Page Aggregate 是否应该存在

这些上位结论已经在关联文档中固定。

本文只做当前阶段最需要的补充收口:

树域已经完成 truth / projection / command 边界的第一轮收口,但主渲染壳仍主要停留在 TypeScript + Next + React。下一阶段要解决的,不再是“树是不是 kernel projection”,而是“树域主执行面怎样继续向 Rust 家族迁移,同时不丢掉现有交互能力”。


2. 当前判断

2.1 已经成立的部分

当前已经成立且不应回退的事实:

  • tree-first graph kernel 继续是树域真相层。
  • Convex 继续承担存储、实时同步、内容与协作底座。
  • mnote-web 已经具备树域 projection / command / transport 的正式入口能力。
  • sidebar_tree / page_tree / file_tree 已经形成同一 projection family。
  • 树域主路径不应再回到“前端自己定义第二套树真相”。

也就是说,当前真正成立的结构是:

  • Rust kernel 持有树语义。
  • Convex 提供 substrate。
  • Rust web 已开始承接 route / projection / command / stream。
  • 当前主站中的树 consumer 已经开始消费 projection family。

2.2 仍未完成的部分

当前仍未完成、且正是下一阶段主任务的部分是:

  • page tree / file tree / picker 的主渲染壳仍主要是 TypeScript + Next + React
  • file_tree 的一部分 row 语义仍由前端 adapter 继续补齐,而不是完全由 Rust 直接输出。
  • tree.* 的长期命令面虽已冻结,但主调用路径仍未完全退出 documents.* 兼容入口。
  • 树域 realtime 仍未完全收口为 Rust Web 正式 snapshot + delta + resync 主链。
  • Sidebar 整体仍是超大客户端壳,树域虽然已收 truth,但执行面与宿主边界还不够薄。

因此当前正确判断不是:

  • “树域 Rust 家族化已经完成”

而是:

树域已经完成“语义与协议收口”,但还没有完成“主执行面 Rust 家族化”。


3. 为什么继续 Rust 家族化有真实意义

3.1 不是语言洁癖,而是减少第二套运行时语义

如果长期保持下面这种结构:

  • Rust 负责 kernel / query / command / projection
  • Next/React 继续负责主树 UI、主交互壳、主状态骨架

那么树域会长期同时维护两套复杂度:

  1. Rust 侧的 projection / command / stream 语义
  2. 前端壳里的 row model / selection / focus / keyboard / DnD / fallback / adapter 语义

这会带来:

  • 协议在两侧重复解释
  • 调试时要同时跨 TS / Rust 两套执行面
  • tree shell 的边界始终无法真正稳定
  • 后续一切性能优化都要先穿过旧前端壳

因此这里的“继续 Rust 家族化”真正要减少的,不是文件后缀的种类,而是:

树域存在两套长期执行语义的状态。

3.2 对加载速度与运行成本有真实潜力

树域是高频常驻 UI,不是偶尔打开一次的边缘面板。

如果它继续作为大型 use client 组件族存在,就会长期保留这些成本:

  • 客户端组件挂载
  • 虚拟列表初始化
  • DnD 状态机初始化
  • 菜单与选择状态初始化
  • 浏览器侧 row model 构建
  • 兼容 fallback 与 stream 选择逻辑

这些成本不会因为“数据真相已经交给 Rust”而自动消失。

把树域主壳继续迁向 Rust 家族,真实收益主要来自:

  • 进一步压低浏览器端常驻 JS
  • 让 projection -> renderer 的路径更短
  • 减少 hydration 与挂载层数
  • 降低 Sidebar 切页与刷新时的重渲染放大
  • 为后续更彻底的 server-first 壳收口创造条件

这里必须强调:

  • Rust 化 不自动等于 更快
  • 但在当前项目的长期方向里,Rust 家族化是“继续减轻旧前端壳”的必要手段

3.3 对协作冲突与长期维护也有真实意义

这里的“冲突”不只指 git merge 冲突,更主要是:

  • projection contract 与 renderer 行为漂移
  • TS adapter 与 Rust route 的边界反复变化
  • 同一个交互在两侧同时维护 legality / normalization / fallback

当树域主执行面仍留在 React 壳里时:

  • Rust 改协议
  • 前端就要继续补 adapter
  • 测试也要跨两族运行时拼接验证

继续 Rust 家族化的意义,是让下面这条链尽量收敛为一条语言家族更统一的主链:

  • kernel truth
  • projection
  • tree command
  • tree shell
  • renderer

4. 下一阶段剩余架构事项

下面这些事项,才是树域继续 Rust 家族化时真正还没完成的主任务。

4.1 正式定义“树域主执行面”的完成标准

首先必须明确:

  • “树域已经吃 projection” 不等于 “树域已经 Rust 家族化完成”
  • “存在 Leptos scaffold / Rust tree_shell 模块” 不等于 “主路径 renderer 已迁完”

下一阶段完成标准应固定为:

  • 至少一条真实默认用户流量,主树 renderer 不再依赖当前 React PrivateTree / FileTree
  • page tree / file tree / picker 的核心交互骨架不再由 Next/React 主壳承担
  • TS 宿主只保留挂载、局部桥接、页面路由与极薄 compat

如果这一标准不先冻结,后续很容易再次把“有 Rust route”误当成“已经 Rust 化完成”。

4.2 把 page tree renderer 真正迁入 Rust 家族

page tree 下一阶段不是继续补前端 helper,而是把以下能力迁成 Rust 家族正式 renderer 能力:

  • 行渲染
  • 展开/折叠
  • 当前页高亮
  • hover 动作区
  • 键盘导航
  • 拖拽反馈
  • 上下文菜单入口

这里的重点不是“把视觉样式翻译一遍”,而是:

  • 把行级行为骨架从 React 组件迁走
  • 让 page tree 只围绕正式 projection item 工作
  • 不再由现有 TS 组件长期持有主路径交互状态机

4.3 把 file tree 从“前端 adapter 文件树”收口为“Rust 直接输出 + Rust 家族 renderer”

file_tree 是当前最关键也最容易退化的一段。

下一阶段必须同时做两件事:

  1. Rust 侧继续把 file_tree 输出补完整。
  2. renderer 不再依赖当前前端在 pageRows + assets 上继续拼 visible rows。

必须继续向 Rust 收口的内容包括:

  • index.md
  • 附件
  • mindmap 文件夹
  • 导图子附件
  • 表格、书籍、PDF 等对象提示
  • resource_kind / asset_kind / icon_hint

否则文件树即使换了新壳,也仍然只是:

  • “页面树 + 前端附件补丁”

这不符合长期目标。

4.4 把树域交互骨架拆成可替换的正式模块

下一阶段不应继续把交互都堆在单一大组件里,而应显式收口为几类正式模块:

  • row model
  • selection model
  • focus model
  • keyboard model
  • DnD state machine
  • context action registry

无论这些模块最终落在:

  • Leptos
  • 或极薄 Rust/TS bridge

都必须满足两条:

  • 它们不再定义结构真相
  • 它们可以独立测试与演进

4.5 完成 tree command cutover Stage 2

树域继续 Rust 家族化时,命令面不能长期继续停在双轨。

下一阶段必须完成:

  • 主路径默认发 tree.*
  • documents.* 退到 compat
  • legality / normalize / move target 等树策略继续回收给 Rust

否则会出现一个长期问题:

  • UI 壳换成 Rust 家族了
  • 但命令面仍主要经由旧 documents.* 兼容语义运行

这样并没有完成真正的主执行面收口。

4.6 完成 Rust Web realtime contract

树域如果要继续往正式主链推进,realtime 必须从“可用”进入“单一正式合同”。

下一阶段需要补齐:

  • snapshot
  • delta
  • resync
  • cursor 漂移处理
  • 局部 subtree 与 workspace scope 的统一

目标不是简单保住 fallback,而是让树域主路径不再依赖:

  • 查询快照
  • 本地 freshness 选择
  • React 侧补偿式同步

4.7 收薄宿主边界

长期目标不是让主站彻底消失,而是让主站对树域只保留最小宿主职责:

  • 页面布局挂载位
  • 路由跳转
  • 样式容器
  • 极薄 feature flag / compat
  • 与其他页面面板的最小桥接

不应继续保留在宿主中的内容:

  • 树结构重建
  • 主交互状态骨架
  • 文件树资源行语义补丁
  • 主要 keyboard / DnD / selection 逻辑

5. page tree 迁移时必须保留的能力

page tree 在迁移到 Rust 家族主执行面时,必须显式保证下面这些能力不退化。

5.1 结构与导航

必须保留:

  • 稳定的层级展开/折叠
  • 当前页高亮
  • 祖先自动展开
  • 搜索/过滤后层级仍可理解

禁止退化为:

  • 纯扁平列表
  • 只有打开功能、没有层级语义的按钮组

5.2 行级动作

必须保留:

  • 新建子页面
  • 重命名
  • 移动
  • 归档/恢复类上下文操作入口
  • 行级 hover 动作区

要求:

  • 不能为了换 renderer 把动作缩减到“点开页面 + 更多菜单”
  • 不能丢失当前工作区级高频动作入口

5.3 键盘与焦点

必须保留:

  • 上下移动
  • 左右展开/折叠
  • Enter 打开
  • 稳定的 focus 行

要求:

  • focus 不能重新混成 selected
  • 展开与选择变化后焦点归一化必须稳定

5.4 拖拽与移动

必须保留:

  • 基础拖拽排序
  • 父节点切换
  • 非法拖拽校验

要求:

  • drop feedback 不能退化成不可预测的闪烁
  • 目标父节点与位置推导必须有稳定、可测试的协议

5.5 大树体验

必须保留:

  • 稳定滚动
  • 大树下的可见区域性能
  • 展开/折叠与切页不会出现明显回闪

这部分是迁移时的硬验收项,不是可选优化项。


6. file tree 迁移时必须保留的能力

file_treepage tree 更容易因迁移而退化。

下一阶段必须把“功能保留”明确写成硬门槛。

6.1 资源层级

必须保留:

  • 页面
  • index.md
  • 附件
  • mindmap 文件夹
  • 导图子附件
  • 表格、书籍、PDF 等资源对象语义

禁止退化为:

  • 页面树下挂一个普通附件列表
  • mindmap 资源被拍平成普通文件

6.2 选择能力

必须保留:

  • 单选
  • 多选
  • Shift 范围选
  • 右键选中
  • 可见行变化后的选择归一化

这部分如果退化,文件树就不再是资源管理器语义,而会退回文档树换皮。

6.3 打开与操作

必须保留:

  • 单击选择
  • 双击打开资源
  • 资源级右键菜单
  • 按资源类型分支的动作入口

要求:

  • 资源图标语义必须稳定
  • asset_kind / icon_hint 不允许再次回到壳内临时猜测

6.4 拖放

必须保留:

  • 内部拖放
  • 外部文件拖入上传
  • copy / move 区分
  • 非法投放校验

要求:

  • 文件树不能只保留视觉拖拽,没有正式动作协议
  • 外部文件拖入必须继续是正式主路径能力

6.5 文件树特有的可见行模型

必须保留:

  • doc -> index -> asset-folder -> asset 的可见行语义
  • 扁平化 rows 与深度的稳定映射
  • 可见行变化后的选择、焦点、拖放范围归一化

这里允许实现换掉,但不允许语义丢掉。


7. 推荐迁移顺序

为了尽量保持体验不退化,推荐顺序如下:

  1. 先补齐 file_tree 的 Rust 直接输出,避免迁 renderer 时还要继续背前端 adapter。
  2. 再把 page tree renderer 迁入 Rust 家族,因为它对象更单纯、验收面更小。
  3. 然后迁 file tree renderer,因为它依赖更多资源与交互语义。
  4. 再迁 picker 轻量模式,让它复用同一套 renderer / state family。
  5. 最后继续削薄宿主,收掉剩余主路径 React 树壳。

原因:

  • page tree 先迁可以先验证主行 renderer 与状态骨架。
  • file_tree 后迁可以避免一开始就在最复杂对象面上同时处理 renderer 与 contract 漂移。
  • picker 最适合作为共用 renderer 的轻量消费场景,而不是主线路的先导。

8. 迁移阶段的验收门槛

只有同时满足下面几条,才可以把树域继续 Rust 家族化的某一阶段视为成立:

  • 页面树与文件树都没有因切流而减少已有能力。
  • page tree / file tree 的关键能力有 smoke 覆盖:
    • 切页
    • 展开/折叠
    • 拖拽
    • 右键菜单
    • 多选与范围选
    • 外部文件拖入
  • file_tree 的对象投影不再依赖前端临时补丁维持主路径。
  • 主调用路径默认走正式 tree.* 命令面。
  • 正式 realtime 至少已经进入统一 snapshot + delta + resync 合同,而不是继续主要靠补偿式 freshness 选择。
  • 主站宿主不再持有树结构真相,也不再承担主要树域交互状态机。

9. 当前优先级建议

在当前总优先级下,树域继续 Rust 家族化的最近顺序建议固定为:

  1. 继续推进 4-6 tree command protocol cutover stage2
  2. 明确 file_tree 直接输出的剩余缺口,并以 Rust 侧补齐
  3. page tree / file tree 迁移补正式功能保留回归矩阵
  4. 选择并落一条真实默认流量进入 Rust 家族 renderer
  5. 再逐步收掉当前主路径 React 树壳

也就是说,当前下一步不是:

  • 继续在现有 React 树壳里堆更多交互补丁

而是:

在功能不退化的前提下,把树域从“Rust 持有语义、React 持有主执行面”的过渡态,推进到“Rust 家族同时持有语义与主执行面”的下一阶段。


10. 最终结论

当前树域继续往全 Rust 方向发展,是有真实意义的。

意义不在于:

  • 代码库里减少一种语言

而在于:

  • 收掉旧前端壳的长期主执行职责
  • 减少第二套复杂运行时语义
  • 为首屏与常驻交互链路继续减重
  • tree-first graph kernel -> Rust Web -> Rust family shell 形成更一致的长期主链

但这个推进必须满足一个前提:

page tree / file tree 的功能能力不能因为迁移而退化。

因此,下一阶段的正确目标不是“尽快把组件翻译成 Rust”,而是:

先把剩余 projection / command / realtime / host 边界补齐,再以 page tree 与 file tree 的能力保留为硬约束,把树域主执行面稳步迁入 Rust 家族。