# RD-39 — The wizards' `seed` input never arrived Status: done Source: found while planning the machine-wiring migration (ADR-0007 arc) ## Why All three wizard containers read their `seed` input **in the constructor**: ```ts const seeded = this.seed(); // always the `initial` default queueMicrotask(() => seeded !== initial ? this.dispatch({ tag: 'Seed', state: seeded }) : this.draftSync.resume(), ); ``` Angular binds component inputs **after** the constructor runs. So `seeded` was always the `initial` default, `seeded !== initial` was always false, and every mount took the `draftSync.resume()` branch. The `seed` input was dead code. The two single-step forms built on the same idiom prove the diagnosis by contrast. They read the input **inside** the microtask, and they work: ``` change-request-form.component.ts:191 queueMicrotask(() => this.dispatch({ tag: 'Seed', state: this.seed() })); besluit-form.component.ts:176 queueMicrotask(() => this.dispatch({ tag: 'Seed', state: this.seed() })); ``` ## Impact Every seeded wizard story rendered step 1 instead of the state it asked for — 21 stories across the three wizards. Storybook is this repo's UI test surface (CLAUDE.md "Testing"), so the states that had no other coverage were exactly the ones silently not rendering: `Submitting`, `Submitted`, `Failed`, `Ingediend`, `Mislukt`. Nothing caught it. `.storybook-ssp/test-runner.ts` runs axe only — it checks that whatever rendered is accessible, never that the right thing rendered. `intake-wizard.component.spec.ts` had worked around it by calling `componentInstance.dispatch(...)` instead of setting the input, which is the shape of a test written against a broken input path. **Production was unaffected**: no route binds `seed`, so the resume branch was always the correct one there. ## Decisions 1. **Read `seed()` inside the microtask**, matching the two forms. Six lines across three files. The `if/else` replaces the ternary because the branches are statements, not values. 2. **Keep the microtask.** It is what defers the dispatch past input binding. The larger fix — `start(seed)` on an application store called from `ngOnInit` — belongs to the ADR-0007 migration, not here. This ticket makes the existing seam correct; it does not move it. 3. **Turn the workaround into the regression test.** `intake-wizard.component.spec.ts` now mounts through `componentRef.setInput('seed', …)` via a `mountSeeded` helper, and a new `honours the seed input` case asserts the machine state directly. Both fail on the old code, which is the point. 4. **Do not touch `draftSync.enabled`.** `enabled: () => this.seed() === initial` reads the input lazily inside a lambda called from an effect, so it was already correct. Changing the input to `| null` is part of ADR-0007. ## Verification performed - `npx ng test ssp` with the intake fix reverted: **2 failed** (both new spec cases). With the fix: **319 passed**. That differential is the proof. - `npm run ci --full` green, including 112 storybook a11y tests. The newly rendered markup (``, error alerts, ``) produced **no** axe violations — the predicted a11y fallout did not happen. - Browser check against the built Storybook, seven seeded stories across all three wizards, each asserted to contain text only reachable from its seed (`Netwerkfout` for `Failed`, `referentienummer` for `Ingediend`, `Documenten` for step 3), plus a negative control that step 1 does **not** show step 3's title. All seven pass. ## Trap for the next person `Failed`, `Submitted`, `Ingediend` and `Mislukt` are unreachable without a network submit, so they can only be produced by a seed. If a future change breaks the input path again, those four stories silently fall back to step 1 and axe still passes. The spec added here is the guard; keep it.