BLOBBO/lanes
Claude e34773d35f harden asset runtime: guard the swap path, bound the boot, reconcile slots
The three that stopped a pack shipping:
 - a mesh-less GLB (armature-only export) fired onSwap anyway, hiding the
   primitive and adding nothing — an invisible prop with a live collider.
   Mesh count is now checked BEFORE the scene is touched, in one guard that
   covers every consumer including slotObject/blob.face.
 - the fulfilment path had no try/catch, so a throw became an unhandled
   rejection. Split in two: a build failure bails out before onSwap can hide
   anything; an onSwap failure keeps the replacement parented, because
   consumers hide their primitive on onSwap's first line and removing the fit
   node there would manufacture the one forbidden state.
 - preload() awaited every url forever. Each is now raced against a 10s
   deadline with allSettled semantics: a stalled host costs one warning and a
   fallback prop, not a game that never boots.

Also:
 - instantiate/instanceSync never throw — createBlob's call site is frozen and
   unguarded, so a throw there is a black screen.
 - ghost and blob share fitBodyToRadius(); a borrowed blob.body was rendering
   the ghost 2.17x oversized with the farm mesh.
 - skinned blob.body is rejected loudly instead of silently half-working; the
   idle-clip mixer is gone (it animated an orphaned skeleton in the fixed step).
 - paintableInfo counts UV islands: blobbo-base.glb passes every other check
   and still paints wrong at 1140 charts. Warning, not rejection.
 - slots.ts gains cannon.base, course.finish, course.tunnel, course.tramp, all
   hooked except tramp (built in frozen game.ts).
 - manifest ignores _-prefixed metadata keys instead of calling them typos.

Empty-manifest parity verified byte-for-byte: scripts/sacred-parity.check.ts
fingerprints the built scene and reports 49df4f20 on main and on this branch.
2026-07-19 12:12:07 +10:00
..
LANE-A-engine-feel.md Foundation: vite+ts+three+rapier scaffold, frozen contracts, lane docs A-E 2026-07-17 19:55:43 +10:00
LANE-B-paint.md Foundation: vite+ts+three+rapier scaffold, frozen contracts, lane docs A-E 2026-07-17 19:55:43 +10:00
LANE-C-machine.md Foundation: vite+ts+three+rapier scaffold, frozen contracts, lane docs A-E 2026-07-17 19:55:43 +10:00
LANE-D-netcode.md Foundation: vite+ts+three+rapier scaffold, frozen contracts, lane docs A-E 2026-07-17 19:55:43 +10:00
LANE-E-art.md Foundation: vite+ts+three+rapier scaffold, frozen contracts, lane docs A-E 2026-07-17 19:55:43 +10:00
LANE-F-audio.md Lane docs F (audio), G (colour zones/puddles/MEGA-MINI), H (ghost/title) 2026-07-18 11:31:41 +10:00
LANE-G-zones.md Lane docs F (audio), G (colour zones/puddles/MEGA-MINI), H (ghost/title) 2026-07-18 11:31:41 +10:00
LANE-H-ghost-title.md Lane docs F (audio), G (colour zones/puddles/MEGA-MINI), H (ghost/title) 2026-07-18 11:31:41 +10:00
LANE-I-asset-runtime.md harden asset runtime: guard the swap path, bound the boot, reconcile slots 2026-07-19 12:12:07 +10:00
LANE-J-workshop-editor.md Workshop plan + lane docs I (asset runtime) and J (editor) 2026-07-18 15:30:09 +10:00