fix(items): don't clobber a same-commit settled flag (cached-model race)#485
fix(items): don't clobber a same-commit settled flag (cached-model race)#485wass08 wants to merge 1 commit into
Conversation
A CACHED item model mounts in the same React commit as its retry wrapper. Child effects run first, so ModelRenderer wrote settled=true — and the wrapper's mount effect then blindly reset it to false, forever: the item rendered and exported fine but its dirty mark never cleared. Fresh-browser loads (every local test) go through suspense and settle later, so this only bit the bake worker, whose shared warm HTTP cache mounts most models synchronously — every warm bake waited out the full readiness cap and falsely reported loaded items as skipped. The settled flag is now URL-stamped: the wrapper's mount effect only un-settles when the URL actually differs from the one already settled, so the child's same-commit write wins on cached mounts and a real model swap still resets state (the URL key remount covers the retry budget). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ab3db67. Configure here.
| const group = ref.current as (Group & { userData: Record<string, unknown> }) | null | ||
| if (!group) return | ||
| if (group.userData.itemModelSettled && group.userData.itemModelSettledUrl === url) return | ||
| group.userData.itemModelSettled = false |
There was a problem hiding this comment.
Remount preserves stale settled flag
High Severity
When ModelWithRetry remounts (e.g. node.asset.src key change) but resolveCdnUrl yields the same URL, unsettleForUrl returns early if itemModelSettled is already true for that URL. Stale userData on the parent group can survive from a prior terminal skip or load, so ItemSystem may clear the dirty mark while the GLB is still loading and scene-ready can fire too early for bakes.
Reviewed by Cursor Bugbot for commit ab3db67. Configure here.


What does this PR do?
Fixes the effect-ordering race behind tonight's slow office bake: a cached item model mounts in the same commit as
ModelWithRetry, child effects run first (settled=true), and the wrapper's mount effect then stomped it back tofalsepermanently. The item renders and exports fine — the artifact was complete — but its dirty mark never clears, so scene-ready waits out the fullsceneReadyMaxWaitMscap and the bake page falsely reports the loaded items as skipped.Only the bake worker hits this (shared warm HTTP context → synchronous cached mounts); every fresh-browser local test loads via suspense and settles after the wrapper's effect, which is why it validated clean locally.
The settled flag is now URL-stamped:
unsettleForUrlis a no-op when the flag is already settled for the same URL (the cached same-commit case), and still resets on a genuine model swap (the URL-keyed remount keeps the retry-budget reset).How to test
bun dev,/bake/demo_office?disable=postFx,draw— settles organically (~2.5s), full artifact,skippedItemsabsent.Screenshots / screen recording
N/A.
Checklist
bun devbun checkto verify)mainbranch🤖 Generated with Claude Code
Note
Medium Risk
Touches scene-ready / bake gating via
itemModelSettledin ItemSystem; behavior change is narrow but timing-sensitive for headless exports.Overview
Fixes a React effect-ordering bug where cached GLBs could render correctly but never clear the item “settled” dirty mark, so headless bakes waited until
sceneReadyMaxWaitMsand falsely reported skips.ItemRendererreplaces the booleansetSettledcallback with aSettleControlthat writesitemModelSettledtogether withitemModelSettledUrl.ModelWithRetrycallsunsettleForUrl(url)on mount instead of always forcing unsettled — it is a no-op when the flag is already settled for that same URL (childModelRenderereffect runs first on synchronous cache hits). Genuine asset swaps still reset because the component is keyed by URL.settle(url)is used when the model resolves, on terminal load failure, and for room-clear preview.Reviewed by Cursor Bugbot for commit ab3db67. Bugbot is set up for automated code reviews on this repo. Configure here.