# 4-25 FileTree view-state model-driven lazy reveal v1

> 创建时间：2026-06-02
>
> 状态：`process`
>
> Owner：04-tree-domain / mnote-web FileTree runtime
>
> 参考：VSCode `AsyncDataTree` / Sidex extension tree view

## 1. 背景

MNote FileTree 已保存 `expandedRelativePaths / selection / scrollTop`，但历史实现把 view-state 恢复成首屏 DOM 递归展开动作。打开 `design` 这类目录时，浏览器需要扫描已有 DOM、逐个展开历史目录、重复同步 selection，容易产生长任务和强制布局。

VSCode / Sidex 的关键不是“保存展开路径”本身，而是：

- view-state 是树模型输入，不是首屏 DOM 脚本。
- children 由 tree data provider 懒加载。
- active item reveal 只解析命中的父链。
- 保存状态与恢复状态分离，恢复过程不反复写回存储。

## 2. 目标

- 打开 scoped FileTree 时首屏只渲染 scope 的直接子层。
- 打开文档页时，只 reveal 当前 active 文档的父链。
- 历史 expanded view-state 不触发全量递归 DOM 展开。
- selection 同步不读取 layout，避免强制 reflow。
- view-state 保存继续保留用户展开、选择和滚动位置。

## 3. 非目标

- 不引入 VSCode `AsyncDataTree` 源码。
- 不重写整个 Sidebar。
- 不改变 Resource Tree / File Tree / Page Tree 的事实源边界。
- 不删除已有用户 view-state。

## 4. Checklist

- [x] 为 `fileTreeScope=design` + active document 位于 `design/07-ai/done/*.md` 增加 SSR reveal 测试。
- [x] local-folder FileTree snapshot 支持在 scoped parent 下附加 active 文档父链。
- [x] document shell 使用 scoped FileTree reveal，而不是只加载 scope 根子项。
- [x] view-state 恢复只影响当前可见层，不递归拉取历史所有 expanded path。
- [x] selection 同步不得读取 `offsetParent/getClientRects`。
- [x] 冷浏览器 smoke 验证从欢迎页打开 `design` 再打开 7-45：FileTree 与文档首屏亚秒级可交互。
- [x] CodeGraph 同步并确认索引状态。

### 2026-06-02 可见 expanded 空目录 idle hydrate

- [x] 重新登录后仍保留首屏轻量策略：不递归恢复所有历史 expanded path。
- [x] 已展开且当前可见、但未加载 children 的 FileTree folder，在 idle 阶段按小批次补加载一层 children。
- [x] idle hydrate 只针对当前 DOM 可见行，不改变 active 文档父链 reveal 的同步边界。
- [x] 新增 runtime 结构测试，防止 view-state restore 重新回到递归 `.then(...restore...)` 模式。

## 5. 验收

- 隐私窗口打开 `design` 不因历史展开目录触发多层 `/api/tree/projections/file/children`。
- 打开 `7-45-chatonly-api-provider-runtime-v1.md` 时 FileTree 能看到 `design/07-ai/done` 父链和 active 文件。
- 表格内容正常显示；当前 dev-hot 冷浏览器仍观测到 Tiptap wasm-bindgen snippets/hydration 约 18 秒延迟，作为独立编辑器 runtime 性能债，不混入本轮 FileTree view-state 修复。
- 无新增轮询或定时刷新链路。
- 重新登录后，如果用户历史展开的可见目录只剩下向下箭头但没有 children，首屏完成后的 idle 小批次补加载应恢复一层文件细节。
