c765483947
`insertByPosition` считал узел незагруженным только при `children === undefined`, но канонический незагруженный вид в этом коде — `children: []` с `hasChildren: true` (его ставит `pageToTreeNode`, к нему сбрасывает свёрнутые ветки `pruneCollapsedChildren`). Для реального незагруженного узла guard `=== undefined` не срабатывал → в пустой список вставлялся `[node]` → lazy-load gate видел `length !== 0` и не догружал остальных серверных детей папки (скрыты до полной перезагрузки) — тот же класс потери данных #159 #1. - Новый общий предикат `treeModel.isUnloadedBranch(node)`: `hasChildren === true && (children == null || children.length === 0)` — единый источник истины для «отложить ли фетч/материализацию». - `insertByPosition` использует его вместо `=== undefined`; для действительно пустой папки (`hasChildren: false`) вставка первого ребёнка сохраняется. - gate в `handleToggle` (`space-tree.tsx`) переведён на тот же хелпер, чтобы предикаты больше не разъезжались (R3). Тесты: юнит на `isUnloadedBranch`; `insertByPosition` не материализует `[node]` в `children:[]`+`hasChildren:true` (и оставляет ветку незагруженной), но вставляет в genuinely-empty. Мутация: старый `=== undefined` предикат краснит эти тесты (в т.ч. на уровне `applyMoveTreeNode`). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>