Skip to content

editor: gate Load Build behind a verification dialog#320

Merged
wass08 merged 1 commit into
mainfrom
feat/load-build-verification-dialog
May 20, 2026
Merged

editor: gate Load Build behind a verification dialog#320
wass08 merged 1 commit into
mainfrom
feat/load-build-verification-dialog

Conversation

@wass08
Copy link
Copy Markdown
Collaborator

@wass08 wass08 commented May 20, 2026

What does this PR do?

Loading a JSON build previously called setScene blind and could crash the editor on schema-invalid input (e.g. items missing asset from a buggy IFC export). This PR gates Load Build behind a verification dialog that parses + validates the file first.

  • New validateBuildJson in @pascal-app/core — pure pre-flight: structural errors (missing nodes / rootNodeIds, no valid roots, duplicate keys), per-node Zod parse with full SchemaIssue[] detail, orphan-parent / unknown-type / no-building / no-levels warnings, plus floor-area sum across slab polygons (minus holes).
  • New LoadBuildDialog — title + ✓/✗, filename + size + node count, errors block (red), structure summary per node type (sites, buildings, levels, walls, doors, windows, items, slabs, ceilings, zones, scans) with floor area row, warnings block, collapsible Schema Details list grouped by node type (every failure shown — no truncation). Import is blocked on any hard error.
  • Settings Panel handleFileLoad now parses → validates → opens the dialog. setScene is deferred to confirm.

Two schema bugs surfaced by the validator on real saves are fixed in the same PR:

  • SiteNode.children is now z.array(z.string()) — every other node has used id arrays for years, and SiteRenderer / use-editor / site-panel all carried a typeof child === 'string' ? child : child.id ternary. The default-scene seed in use-scene.ts and the photo-to-scene MCP builder now pass building.id instead of the full object. migrateNodes flattens legacy nested-object children on load so older saved scenes still import.
  • LevelNode.children now includes shelf — the editor allowed shelves parented to a level but the schema's union didn't list them, so a clean save → load roundtrip failed validation. The schema-vs-registry-as-source-of-truth discussion (drop the unions entirely and lean on relations.hosts) is captured in plans/editor-node-registry.md under Open questions in the private-editor repo.

How to test

  1. bun dev:community (or the standalone editor) and open the build editor.
  2. Open Settings → Save Build → save the current scene as JSON.
  3. Settings → Load Build → pick the saved file. Dialog appears titled "Ready to import" with the structure summary + floor area. Click Replace current scene → scene swaps cleanly.
  4. Load editor/packages/core/... or any IFC-converter output with bad nodes (items missing asset, doors with scalar position, etc.). Dialog title becomes "Cannot import this file", the error block lists the failure count, and the Schema Details section enumerates every failing node with nodeId · path — message. Import button is disabled.
  5. Try loading an invalid JSON file (e.g. a .txt). Dialog opens with "File could not be parsed as JSON".
  6. Load an empty object {}. Errors list both missing-nodes and missing-rootNodeIds.

Screenshots / screen recording

N/A here — happy to add a short clip if useful.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

🤖 Generated with Claude Code

Loading JSON previously called setScene blindly and crashed when
the file held schema-invalid nodes (e.g. items missing `asset`).
The new dialog parses the file, runs validateBuildJson in core,
and surfaces structure counts (site/building/levels/walls/doors/
windows/items/slabs/ceilings/zones/scans), floor area, and a
per-node Schema Details list grouped by type. Import is blocked
when any hard error exists.

Two schema bugs the validator surfaced are fixed here too:

- SiteNode.children is now an id array like every other node
  (was a discriminatedUnion of full objects; three readers carried
  a string-or-object ternary that's now dropped). migrateNodes
  flattens legacy nested-object children on load. Default-scene
  seed and photo-to-scene MCP builder updated to pass `building.id`.
- LevelNode.children now includes shelf — the editor allowed it
  but the schema didn't. The schema-vs-registry-as-source-of-truth
  discussion is captured in plans/editor-node-registry.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mintlify
Copy link
Copy Markdown

mintlify Bot commented May 20, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
pascal 🔴 Failed May 20, 2026, 2:31 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@wass08 wass08 merged commit 6ea622a into main May 20, 2026
1 of 2 checks passed
wass08 pushed a commit that referenced this pull request May 21, 2026
Fixes breakage introduced by #320 which changed `SiteNode.children` from
embedded `BuildingNode | ItemNode` objects to flat `string[]` IDs.

- `packages/mcp/src/lib/rehydrate-site-children.ts`: replace now-obsolete
  re-embedding logic with a no-op passthrough (call-site compatible)
- `packages/mcp/src/tools/variants/generate-variants.ts`: drop the inline
  copy of the same function and its call
- `packages/nodes/src/site/renderer.tsx`: cast `childId as AnyNodeId` since
  `SiteNode.children` is now `string[]`, not `AnyNodeId[]`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wass08 pushed a commit that referenced this pull request May 21, 2026
PR #320 changed SiteNode.children from embedded BuildingNode/ItemNode
objects to flat string[] IDs. PR #325 updated the runtime call sites
but missed the three scene templates, which still mutated the site
node's children array to embed full building objects after building
the flat dict. This caused AnyNode.safeParse to fail for site_empty,
site_2br, and site_garden in bun test --cwd packages/mcp.

Remove the obsolete mutation blocks; each template already initialises
site.children with the correct string id (e.g. ['building_empty']).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

1 participant