Skip to content

fix(nodes): guard missing roof-segment trim in ridge-vent geometry key (Sentry MONOREPO-EDITOR-ED) - #530

Merged
Aymericr merged 1 commit into
mainfrom
fix/sentry-EDITOR-ED
Aug 4, 2026
Merged

fix(nodes): guard missing roof-segment trim in ridge-vent geometry key (Sentry MONOREPO-EDITOR-ED)#530
Aymericr merged 1 commit into
mainfrom
fix/sentry-EDITOR-ED

Conversation

@anton-pascal

@anton-pascal anton-pascal commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • tolerate roof segments whose stored data predates the trim schema field
  • keep the ridge-vent geometry dependency key stable by reading trim fields from an empty partial object when segment.trim is missing

Root cause

The public viewer hydrates raw stored nodes without re-running the Zod parser. For legacy roof segments, that means the RoofSegmentTrim schema default never applies and segment.trim can be undefined at runtime. ridgeVentSegmentGeometryKey then dereferenced trim.left, crashing the viewer.

buildRidgeVentGeometry already routes trim handling through normalizeRoofSegmentTrim, so no additional guard was needed there.

Sentry

  • MONOREPO-EDITOR-ED
  • Issue 7593979332
  • Observed July 22, 2026 on /viewer/project_myTyG1YFgGBVpS6O

Validation

  • bun test packages/nodes/src/ridge-vent/__tests__/geometry.test.ts — 18 pass, 0 fail
  • bunx biome check packages/nodes/src/ridge-vent/renderer.tsx — clean

Note

Low Risk
Small defensive change in ridge-vent rendering; aligns geometry key with existing normalization used elsewhere.

Overview
Fixes a viewer crash when ridge vents render on legacy roof segments that were saved before the trim field existed. The public viewer hydrates nodes without re-running Zod, so segment.trim can be undefined even though parsed segments get defaults.

ridgeVentSegmentGeometryKey now builds its cache key from normalizeRoofSegmentTrim(segment) instead of reading segment.trim directly, matching how buildRidgeVentGeometry already handles trim. A core test documents that segments with no trim at all normalize to zero trim.

Reviewed by Cursor Bugbot for commit 1cdf09a. Bugbot is set up for automated code reviews on this repo. Configure here.

Roof-segments migrated on scene load are cast rather than zod-parsed, so
a segment saved before `trim` existed reaches the renderer with the field
absent and the geometry key crashed reading `trim.left` off undefined.

Route the key through core's `normalizeRoofSegmentTrim`, matching what
`use-segment-trim-clip` and `ridge-vent/geometry` already do. Besides
handling the absent field, this makes the cache key agree with the trim
the geometry is actually built from — an out-of-range trim normalizes to
a clamped value, so keying on the raw field could otherwise vary while
the built mesh did not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Aymericr
Aymericr force-pushed the fix/sentry-EDITOR-ED branch from 25b7add to 1cdf09a Compare August 4, 2026 17:03
@Aymericr

Aymericr commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Confirmed the crash is reachable and taken this slightly further than the original patch.

Why the null is real, since it is worth recording: trim is a required field with a schema default, so it looks unreachable. But the roof-segment branch of the scene-load migration in use-scene.ts builds its result with a cast rather than a zod parse — the comment there says so explicitly for pitch. That means a segment saved before trim existed arrives at the renderer with the field genuinely absent, and the schema default never lands. The Sentry report is not a phantom.

What I changed. The patch used segment.trim ?? {} with a Partial<RoofSegmentTrim> annotation. That fixes the crash, but the two sibling call sites — shared/use-segment-trim-clip.tsx and ridge-vent/geometry.ts — both route through core's normalizeRoofSegmentTrim, so I switched to that for consistency.

It also fixes a second, quieter problem. normalizeRoofSegmentTrim clamps impossible trims: a left/right pair that would invert the footprint gets scaled to fit. The geometry this key guards is built from the normalized trim. Keying on the raw field means two distinct raw values that normalize to the same clamped result produce different keys, so the useMemo rebuilds geometry that is byte-identical. Reading through the same normalizer makes the cache key agree with what is actually rendered.

Added a regression test in roof-segment-trim.test.ts for the trim-absent case, with a comment recording why it is reachable so nobody deletes it as redundant with the schema default.

bun test roof-segment-trim ridge-vent  → 25 pass, 0 fail
bun run check                          → 1583 files, no fixes applied

Pushed to fix/sentry-EDITOR-ED. Will merge once CI is green.

@Aymericr
Aymericr merged commit aa27799 into main Aug 4, 2026
3 checks passed
@Aymericr
Aymericr deleted the fix/sentry-EDITOR-ED branch August 4, 2026 17:07
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