Sprite Lab in Lab2: fix level switch#73854
Open
breville wants to merge 1 commit into
Open
Conversation
The legacy pageConstants reducer forbids changing a key once set - it assumes one page load per level. Lab2 switches levels in place, so navigating between two SpriteLab2 levels threw "Can't change value of key 'channelId'" from the seeding effect and took down the page. The lab now registers the reducer wrapped: a change the legacy guard rejects is re-applied from the initial state (last write wins). Wrapping beats resetting on LifecycleEvent.LevelChangeRequested: the view remounts on level switch and re-seeds the stale channel before the new one loads, so no event-ordered reset can win that race. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
76cfb0e to
36e40fc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Navigating between two SpriteLab2 levels in a lesson crashed the page:
Error: Can't change value of key "channelId", then the error boundary.Root cause
SpriteLab2 seeds the legacy
pageConstantsslice (isBlockly,channelId, …) because it bypassesStudioApp.init, and the legacy reducer forbids changing a key once set — it assumes one page load per level. Lab2 switches levels in place: the new level's channel loads, the seeding effect re-fires with the newchannelId, and the reducer throws mid-dispatch. Single-level sessions never hit it because the firstundefined → valuetransition is legal; it takes a second, different channel.Why not reset on
LifecycleEvent.LevelChangeRequestedTried first — it's the formal seam, and the event does fire. But
SourcesContaineris keyed onlevelProperties.id, so the view remounts on switch and its seed effect re-runs immediately, whilestate.lab.channelstill holds the previous channel. The stale value gets re-seeded right over the reset, and the throw comes back when the new channel lands. No event-ordered reset wins that race.The fix
The lab registers the reducer wrapped (
reseedablePageConstants): delegate to the legacy reducer, and when its change-guard throws, re-apply the action from the initial state — last write wins. Correct under any effect ordering, no legacy edits, and no coupling to the legacy module's internal action type (it catches the throw rather than matching type strings). Violations the legacy reducer rejects outright, like disallowed keys, throw again on the retry and so still throw. Classic labs are untouched; the lab's own seeding effect is the slice's only writer on Lab2 pages.Testing
pageConstants.channelIdmatchingstate.lab.channel.idat every step — each level isolated on its own channel.Follow-up
When SpriteLab2 adopts the unified
useSourceshook (#73822), the channel stops flowing throughstate.laband this seam should be revisited — potentially readingchannelIdlive instead of seeding it at all.