Five Critical issues caught in code review of f3423a51. Each one broke
an invariant the original commit claimed to uphold.
1. nestNode: descendants kept their old-depth zIndex after a re-parent.
Now walks the dragged subtree and shifts every descendant's zIndex
by the same depthDelta so "children above ancestors" survives moves
between levels of the hierarchy.
2. bumpZOrder: siblings all share zIndex = depth in fresh topology, so
a single +1 bump was identical for every sibling and subsequent
bumps drifted zIndex unboundedly. Rewritten to sort siblings by
current zIndex and swap the target with its neighbour in the bump
direction — Figma-style reorder, stays within the sibling tier.
3. findDropTarget: depth-first tiebreaker lost to bumped siblings. The
visually-frontmost card after Cmd+] is a shallow sibling, but the
hit test picked the deepest nested card regardless. Swapped order
so zIndex wins first, depth second, area third. Also pre-computes
the depth map once per call (was O(n²) via repeated .find walks —
will matter past ~30 workspaces).
4. arrangeChildren: saved absolute position using `slot + parent.position`,
but parent.position is RELATIVE to its own parent when nested.
Grandchildren's stored x/y were in the parent's local frame and
reload placed them in the wrong spot. Now walks the full ancestor
chain via absOf() to get the true canvas-absolute origin before
PATCHing.
5. setCollapsed: naive flip of every descendant's hidden flag diverged
from the topology rebuild on hydrate. Collapse A, collapse B, then
expand A — C should stay hidden because B is still collapsed, but
before this fix C was unhidden. Rewritten to recompute every
descendant's hidden from the full ancestry chain, matching the
topology pass byte-for-byte. New round-trip test asserts the two
code paths produce identical node.hidden across a full lifecycle.
Also:
- Removed dead cascadeMessage constant (never rendered).
- Replaced hardcoded 260/120 in zoom-to-team with exported constants.
- arrangeChildren PATCH catch now logs instead of silently swallowing.
- Added 70→76 tests: setCollapsed 3-chain scenarios, bumpZOrder swap
semantics, edge-of-list no-op.
All 915 canvas tests green. Backend untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>