Skip to content

Fix white-screen crash: nullable bindings must say null - #17

Merged
alejandro-nexcade merged 1 commit into
mainfrom
alejandro/fix-nullable-bindings
Jul 2, 2026
Merged

Fix white-screen crash: nullable bindings must say null#17
alejandro-nexcade merged 1 commit into
mainfrom
alejandro/fix-nullable-bindings

Conversation

@alejandro-nexcade

Copy link
Copy Markdown
Collaborator

Root cause (systematic-debugging trace)

The app went white because React unmounted the tree on `TypeError: null is not an object (evaluating 'summary.total')` at `ci.ts:69` during board render. The chain:

  1. serde serializes `Option::None` as `null` (key always present — no `skip_serializing_if`)
  2. `#[ts(optional)]` generated `ci_summary?: CiSummary` — claiming absent-or-present, i.e. `undefined`, never `null`
  3. so `ci === undefined ? "none" : ciState(ci)` type-checked while passing runtime `null` straight into `ciState`
  4. test fixtures omitted the field (undefined), matching the wrong type — every suite green, runtime dead

Only reproducible with hydrated reviews (persisted state), which is why headless probes and CI never saw it.

Fix (the class, not the line)

  • Removed `#[ts(optional)]` from the four always-present-null fields (`plan_path`, `dispatch_snapshot`, `ci_summary`, `last_reviewed_sha`); bindings now say `T | null` — the wire truth. tsc immediately surfaced every dishonest guard; all fixed.
  • Fixtures now mirror the wire shape (`null`, not omitted) so tests exercise reality.
  • Regression tests lock the null path (rank, fast lane, mixed board sort).

Verified

cargo test 458 · clippy -D warnings · tsc strict clean · vitest incl. new regressions · vite build.

🤖 Generated with Claude Code

Option fields without skip_serializing_if are always present on the wire
as null, but #[ts(optional)] declared them absent-or-present — so tsc
never forced null handling and ciState(null) dereferenced summary.total
during board render, unmounting the whole app once persisted reviews
hydrated. Bindings for plan_path/dispatch_snapshot/ci_summary/
last_reviewed_sha now say T | null; the two dishonest guards are fixed;
fixtures mirror the wire shape (their omission hid the crash from every
test); regression tests lock the null path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alejandro-nexcade
alejandro-nexcade merged commit 3c38e3e into main Jul 2, 2026
2 checks passed
@alejandro-nexcade
alejandro-nexcade deleted the alejandro/fix-nullable-bindings branch July 2, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants