fix(grid): v3 review fixes — split-null crash, monitor race, drag-safe gutters

Adversarial review (4 lenses → per-finding verify) of v3 confirmed 6 issues:

- HIGH: splitForLayout({"grid-4":null}) threw a TypeError — null passed the
  `!== undefined` guard, then null.cols threw. Since splitForLayout runs on every
  grid render, one corrupt localStorage entry would brick the tab UI. Now guards
  `!== null && typeof === 'object'`.
- MED: a monitor toggled before the session finished attaching (id still null)
  showed the button active while the pane stayed live and sent a resize, and did
  not self-correct. onSessionId now reconciles a pending monitor once the id lands.
- MED: renderGutters destroyed + recreated handles on every applyLayout, dropping
  the drag listeners if a re-render fired mid-drag. A draggingGutter flag now skips
  the rebuild while dragging.
- LOW: grid-presets hardcoded the 1024px breakpoint → now uses GRID_MIN_WIDTH.

Regression tests added (null-split no-throw, attach reconcile, drag survives a
concurrent re-render). typecheck + build:web clean, 1615 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2026-07-11 20:25:04 +02:00
parent 007e598802
commit 733c8a8318
6 changed files with 68 additions and 4 deletions

View File

@@ -303,6 +303,8 @@ export function splitForLayout(splits: GridSplits, layout: GridLayout): TrackSpl
const stored = splits[layout]
const ok =
stored !== undefined &&
stored !== null && // a null entry ({"grid-4":null}) is valid JSON but not a TrackSplit
typeof stored === 'object' &&
Array.isArray(stored.cols) &&
stored.cols.length === cols &&
Array.isArray(stored.rows) &&