@@ -218,6 +218,42 @@ it passes whether or not the `snapshot()` is there:
218218- A subquery renders ** bare ` <div> ` s** for its group header/body, not a ` rule-group ` element
219219 (React's ` RuleWithSubQueryGroupComponentsWrapper ` ), and it is not customizable.
220220
221+ ### The conformance harness (step 6)
222+
223+ ` vitest.conformance.config.ts ` runs ** two projects** , because the two fixture layers demand
224+ opposite render modes. This is structural, not cosmetic — one plugin instance cannot serve both.
225+
226+ | Project | Compilation | Environment | Renders |
227+ | ----------------- | -------------------------------------- | ----------- | --------------------------------------------------------------------------------------- |
228+ | ` conformance-ssr ` | ` generate: 'ssr' ` , ` hydratable: false ` | ` node ` | ` renderToString ` , controlled ` query ` — the ** static** layer |
229+ | ` conformance-dom ` | default ` dom ` | ` jsdom ` | testing-library + ` flush() ` , ** uncontrolled** ` defaultQuery ` — the ** post-flush** layer |
230+
231+ - ** The static layer is rendered server-side deliberately.** The fixtures come from
232+ ` renderToStaticMarkup ` with no effects run; Solid's client ` render() ` runs effects, so the
233+ "extract before the scheduler flushes" trick both prior ports used is unavailable. SSR runs no
234+ effects at all, so this is an _ exact_ match rather than an approximation — and it exercises the
235+ ssr path in all 50 cases for free.
236+ - ⚠️ ** ` solid({ ssr: true, … }) ` on the ssr project is load-bearing** and is _ not_ redundant with
237+ ` solid: { generate: 'ssr' } ` . ` vite-plugin-solid@3 ` injects a ` browser ` condition in test mode
238+ (` isTestMode && !options.ssr ` ), ` @solidjs/web ` lists ` browser ` before ` node ` , and the browser
239+ build's ` renderToString ` is a stub returning ` undefined ` . ` ssr: true ` suppresses the injection
240+ (and the plugin's forced ` environment: 'jsdom' ` ); ` options.solid ` merges last, so the explicit
241+ ` generate ` /` hydratable ` still win. Do ** not** "fix" this by hand-writing ` resolve.conditions ` .
242+ - ** ` hydratable: false ` ** — hydration keys land as _ attributes_ and would break byte-identical
243+ ` class ` comparison. (Marker comments are ignored by extraction; attributes are not.)
244+ - ** ` cases.ts ` carries no rendering.** The render helpers are split into ` render-ssr.tsx ` and
245+ ` render-dom.tsx ` so the ssr project never imports ` @solidjs/testing-library ` and vice versa.
246+ - ** ` scenarios.tsx ` , not ` .ts ` ** — ` getValueEditorSeparator ` returns JSX, which each project must
247+ compile for its own target.
248+ - ⚠️ ** ` actions.solid.test.ts ` must ` flush() ` once after ` createRoot ` before replaying.** Effects
249+ created inside a root are queued, not run eagerly, so the controlled-` query ` sync effect's first
250+ run otherwise lands on the flush _ after_ the first op and silently reverts it. Found the hard
251+ way: 4 of 19 cases failed with the ops apparently never applied.
252+ - ` extract.ts ` exposes both ` extractFromContainer ` and ` extractFromMarkup ` (upstream's
253+ ` schemaVersion ` 2 split). The markup form builds its own ` JSDOM ` when there is no global
254+ ` DOMParser ` , which is what lets the ssr project run in the ` node ` environment and thereby prove
255+ a server render needs no document.
256+
221257### Types
222258
223259- ** ` jsxImportSource ` is ` "@solidjs/web" ` .** ` solid-js@2 ` owns no JSX namespace and no
@@ -241,12 +277,30 @@ it passes whether or not the `snapshot()` is there:
241277** Standing rule: every gate must be proven to fail.** When a step adds a gate, deliberately break
242278it, record that it went red, then revert. A gate that cannot fail is worse than none.
243279
244- Current gates (step 8): ` check:versions ` , ` fmt:check ` , ` build ` , ` check ` , ` check:exports ` ,
280+ Current gates (steps 6 + 8): ` check:versions ` , ` fmt:check ` , ` build ` , ` check ` , ` check:exports ` ,
245281` lint ` , ` test:coverage ` (global 80% lines, plus a per-directory 90% lines on ` packages/*/src/** ` —
246282widened at step 5 from the step-3 ` packages/*/src/reactive/** ` , which it subsumes; both
247- non-vacuous, both proved red with no injected dead code), ` test:ssr ` (** both halves** ), and
248- ` check ` including the examples. (` conformance ` is a stub that exits 0 until step 6; it is not a
249- gate yet.)
283+ non-vacuous, both proved red with no injected dead code), ** ` conformance ` ** (237 assertions: 50
284+ static classnames, 50 accessible descriptions, 50 post-flush classnames, 58 action sequences, 19
285+ port-side action sequences, plus alignment/drift/format), ` test:ssr ` (** both halves** ), and
286+ ` check ` including the examples.
287+
288+ The four step-6 conformance gates were each proved red and reverted:
289+
290+ 1 . ** DOM parity** — ` conformance-gate-probe ` appended to ` ActionElement.tsx ` 's class turned
291+ exactly 100 cases red (50 static + 50 post-flush), which is the split the two projects promise.
292+ 2 . ** ` schemaVersion ` ** — ` EXPECTED_SCHEMA_VERSION = 3 ` made ` conformance:fetch ` exit 1 with the
293+ "update ` test/conformance ` before bumping the tag" message.
294+ 3 . ** Scenario drift** — renaming the local ` allControls ` scenario turned the drift test (and the
295+ three case-alignment tests) red while all 50 rendered cases stayed green.
296+ 4 . ** Value-editor reset** — an early ` return ` in ` createValueEditorReset ` 's apply phase left
297+ conformance at 237/237 green (as upstream predicts: every case is ` differsFromStatic: false ` )
298+ while turning 5 of the 9 post-mount unit assertions red. That asymmetry is exactly why the
299+ plan forbids proving this one through the post-flush fixture.
300+
301+ Separately confirmed: with ` test/fixtures/ ` removed, ` bun run test ` still passes 284/284 and
302+ ` conformance:test ` fails with the actionable "run ` bun run conformance:fetch ` " message rather than
303+ an opaque parse error.
250304
251305The step-8 example gate was proved red twice, independently, and reverted both times:
252306` document.title ` injected into ` QueryBuilder.tsx ` turned the served response into a 500 and took
0 commit comments