Reverse #278's deliberate no-collapse decision for the budget grid: it now
folds/unfolds at every category level like the hierarchical reports, opening
fully collapsed with a one-click "Expand all".
- BudgetTable: wire useCollapsibleGroups (defaultExpanded: false), inline
BUDGET_COLLAPSE_ACCESSORS + BUDGET_EXPANDED_KEY (mirrors ComparePeriodTable /
BudgetVsActualTable — no budgetTableModel.ts). Chevron + aria-expanded +
aria-level on every parent row; groups.visible(group) before reorderRows.
- BudgetTable: section subtotal now uses the tested sumLeavesForType on the RAW
group (drop-in for the hand-rolled loop) so folding stays purely visual.
- BudgetTable: rename STORAGE_KEY to "budget-subtotals-position", decoupling the
subtotals-position preference from BudgetVsActualTable (they collided).
- useBudget: extract the pure buildBudgetYearRows(); the grid's rows are
level-order (BFS), not DFS — document the invariant and pin it in a test, since
the #288 ancestor-walk collapse is order-independent (the v1 plan assumed DFS
and would have broken here).
- Tests: useBudget.test.ts locks the level-order emission, the DFS-killer, the
end-to-end multi-level collapse on real builder output, and that subtotals sum
raw rows regardless of collapse. 828 vitest pass.
Resolves#289
Generated autonomously by /autopilot run of 2026-07-15
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>