RenderVariant.svelte logs a console.error telling the author their controls are broken, on stories whose controls work perfectly.
Reproduce
Open StateOption in the svelte5 or sveltekit book. The console carries:
[poveste] Variant "untitled" has a controls slot but no initState. Controls will render and appear to work, but their edits cannot reach the story: the story is mounted separately for each slot, so a component-local variable is not shared.
Then type into the optionApiData control. The story body updates immediately — "optionApiData": "EDITED-VIA-CONTROL". The edit reaches the story. Every claim in the message is false for this story.
Why
RenderVariant.svelte:32 tests only the variant's own initState prop:
if (!initState && shouldRender && slotName === 'controls' && $$slots.controls && !currentVariant.__pvtStateWarned) {
StateOption declares initState on the Story and the controls snippet on the Variant:
<Hst.Story title="StateOption" initState={() => ({ optionApiData: OPTION_DATA })}>
<Hst.Variant>
{#snippet controls({ state })}
So by the time RenderVariant runs, RenderStory.svelte:27 has already seeded the state and set the flag:
if (initState && currentVariant && !currentVariant.__pvtStateSeeded) {
currentVariant.__pvtStateSeeded = true
currentVariant.state = { ...currentVariant.state, ...initState() }
}
The variant-level check never consults __pvtStateSeeded — the signal it needs, already on the object it already holds. The story-level check in RenderStory is correct; only the variant one is wrong.
Fix
Add the seeded flag to the condition:
if (!initState && !currentVariant.__pvtStateSeeded && shouldRender && slotName === 'controls' && ...)
Ordering matters: RenderStory seeds during its own script, and both mounts run before the controls slot renders, so the flag is set by then. Worth confirming that holds for the iframe layout too, where the two mounts are in different realms — __pvtStateSeeded lives on the variant object, which is per-realm, so the seeding and the check need to be in the same realm to pair up. That is the one thing to verify rather than assume.
Which stories
Six, across both books — a variant-level controls slot while initState sits on the Story:
svelte5/src/stories/StateOption.story.svelte
svelte5/src/stories/StateSetup.story.svelte
svelte5/src/stories/StateSetup2.story.svelte
sveltekit/src/lib/stories/StateOption.story.svelte
sveltekit/src/lib/stories/StateSetup.story.svelte
sveltekit/src/lib/stories/StateSetup2.story.svelte
Stories that declare controls at Story level route through RenderStory and are correctly quiet.
Why this is worse than ordinary noise
The diagnostic is good and the failure it describes is real — UnmigratedState.story.svelte exists as a deliberate fixture so it has something to fire on, and its comment says as much. A false positive on correct code is what teaches people to filter the message out, and the next person to hit the genuine UnmigratedState shape will have already learned to ignore it.
It also fires on three of the repo's own example stories, so the book ships red consoles.
Coverage gap
Nothing catches this. examples/svelte5/playwright/state-sync.spec.ts asserts on page.on('console', …) for the presence of this diagnostic in the unmigrated case, but nothing asserts its absence for a correctly-written story — which is the assertion that would have failed here. A spec that opens StateOption, edits the control, asserts the story body changed and asserts no [poveste] console error, closes both halves.
Found by clicking through the dev server, not by any suite.
RenderVariant.sveltelogs aconsole.errortelling the author their controls are broken, on stories whose controls work perfectly.Reproduce
Open
StateOptionin the svelte5 or sveltekit book. The console carries:Then type into the
optionApiDatacontrol. The story body updates immediately —"optionApiData": "EDITED-VIA-CONTROL". The edit reaches the story. Every claim in the message is false for this story.Why
RenderVariant.svelte:32tests only the variant's owninitStateprop:StateOptiondeclaresinitStateon the Story and thecontrolssnippet on the Variant:So by the time
RenderVariantruns,RenderStory.svelte:27has already seeded the state and set the flag:The variant-level check never consults
__pvtStateSeeded— the signal it needs, already on the object it already holds. The story-level check inRenderStoryis correct; only the variant one is wrong.Fix
Add the seeded flag to the condition:
Ordering matters:
RenderStoryseeds during its own script, and both mounts run before the controls slot renders, so the flag is set by then. Worth confirming that holds for the iframe layout too, where the two mounts are in different realms —__pvtStateSeededlives on the variant object, which is per-realm, so the seeding and the check need to be in the same realm to pair up. That is the one thing to verify rather than assume.Which stories
Six, across both books — a variant-level
controlsslot whileinitStatesits on the Story:Stories that declare
controlsat Story level route throughRenderStoryand are correctly quiet.Why this is worse than ordinary noise
The diagnostic is good and the failure it describes is real —
UnmigratedState.story.svelteexists as a deliberate fixture so it has something to fire on, and its comment says as much. A false positive on correct code is what teaches people to filter the message out, and the next person to hit the genuineUnmigratedStateshape will have already learned to ignore it.It also fires on three of the repo's own example stories, so the book ships red consoles.
Coverage gap
Nothing catches this.
examples/svelte5/playwright/state-sync.spec.tsasserts onpage.on('console', …)for the presence of this diagnostic in the unmigrated case, but nothing asserts its absence for a correctly-written story — which is the assertion that would have failed here. A spec that opensStateOption, edits the control, asserts the story body changed and asserts no[poveste]console error, closes both halves.Found by clicking through the dev server, not by any suite.