* fix(items): retry failed model loads, settle skipped items, keep exports clean
A transient storage failure (observed: Supabase 504s under the bake page's
~200-concurrent-request burst) permanently broke an item for the whole
session: drei's useGLTF caches the rejected load by URL, the per-item
ErrorBoundary swallowed it, and the red debug-box fallback was BAKED into
the exported GLB (observed in a prod artifact). Meanwhile ItemSystem
cleared the dirty mark at group registration — before the model resolved —
so scene-ready could fire while GLBs were still loading, risking exported
placeholder geometry.
- ModelWithRetry: bounded retries (1s/3s) that clear the useGLTF cache
entry and re-mount via the boundary's new resetKey. The timer is owned
by an effect keyed on the failure count, so StrictMode's synthetic
unmount/remount re-arms it instead of silently discarding it (the
naive onError-scheduled timer died exactly that way in dev).
- Exhausted retries settle the item as SKIPPED: the debug box renders
nothing during exports, and the failure lands in
useViewer.itemLoadFailures (nodeId -> url) so a bake host can persist
which items are missing from the artifact.
- ItemSystem holds the dirty mark until the item settles (model mounted,
terminally failed, or never expected) — scene-ready now genuinely waits
for item content; loading placeholders also hide during exports.
- ErrorBoundary: onError + resetKey props.
Verified against a 200+-item prod scene locally: permanent 504 -> exactly
3 fetch attempts, bake completes without the item and without debug
boxes; 504-once -> retry heals, artifact byte-equivalent to the intact
run; no-failure runs unchanged (demo_1 byte-identical).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(items): reset retry budget + settled flag when the asset URL changes
Bugbot: after a terminal load failure, swapping the item's model kept the
stale failures/epoch state and the settled flag — the new URL never even
attempted to load. ModelWithRetry is now keyed by asset src (clean retry
budget per URL) and un-settles the item on mount so the replacement load
is awaited by ItemSystem/scene-ready too.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>