## solidjs/solid — v2.0.0-experimental.10…v2.0.0-rc.0

_1246+ commits._

### Features
- **feat(solid): bare ssrSource "client" suspends as a final hole — the structural form of a browser-only source. Previously "client" required a declared first paint (loadingValue/seedLoadingValue) and a bare declaration was a dev error; the matrix now has both channels. Bare = boundary channel: on the server the source's pending promise is a shared never-settling CLIENT_HOLE — reads suspend finally, and the nearest <Loading> boundary detects the tag and hands the position to the client. Discovered before fragment registration it takes the renderToString route verbatim (plain fallback + "$$f" client-continue marker — no placeholder template, nothing will ever swap); surfacing only after registration (an earlier real async read masked it), it rejects the fragment, the closest streaming analogue since "settle but keep the fallback" is not expressible in the fragment protocol — the client renders that boundary's content fresh after hydration. Read outside a <Loading> boundary it throws a real render error instead of wedging the stream. The tag rides both pending channels (component-body retryPromise and template-hole ret.p via createErrorBoundary's aggregate), and serverEffect gives up on holes instead of blocking. Declared form unchanged: loadingValue/seedLoadingValue stays the value channel (server renders commit #0; client serves it while hydrating, then computes). Client side, the bare-client dev assert and its extra type overloads are gone — the pre-hydration gate returns the shared UNASKED thenable unconditionally so bare nodes stay uninitialized and windowed nodes stay verdict-quiet — and the hydration claim now swallows the settled-rejected _fr promise, so rejected fragments (error finalize or client handoff) stop surfacing unhandled-rejection noise. Parity harness pins all three shapes (bare memo, bare store, late-surfacing hole; the streamed rejected swap splices dom-expressions' single-space rejection template, pinned via expectedTextStreamed). Full bar: turbo 27/27 (parity 85/85); size gates green — client cost is compression noise (raw minified byte-identical; gzip −18..+1 B, brotli +10..30 B across scenarios), the implementation is server-only bytes.** (427dc18)
- **feat: ssrSource "client" requires a declared commit #0 (#2981)** (536dec5)
- **feat(solid): SSR flushes commit #0 — loadingValue/seedLoadingValue render on the server and hydrate as the claimed value, replacing the interim hydration strip. The server never suspends a loading-value source: processResult serves the loading value instead of NotReadyError on every async path (thenable, iterator, hybrid, NotReady-retry from an unready sync dep, ssrSource "client"), the boundary never trips, markup flushes from commit #0, and the landing streams as data through the existing serialization channel. The first-value lock generalizes to commit #0: on serialized paths the HTML-visible value never advances past the loading value (settle callbacks skip the comp.value write; projections mark the pending proxy ready immediately, retargeted at a frozen seed copy, and the V1 freeze skips retargeting), so later-rendered holes in the same response can't tear against already-flushed placeholder markup — landings live in the data channel, exactly as later iterator yields always have. One deliberate exception to "sync results are never serialized": a sync landing after a NotReady retry ships as a resolved promise, because placeholder markup is already on the wire and the client can't re-derive its way out of DOM claimed against commit #0. createSignal's server fn-form forwards loadingValue (it previously dropped everything but deferStream/ssrSource); ServerSsrOptions gains seedLoadingValue and createProjection applies it across all four async branches. Client side, the strip (stripLoadingValue) is deleted: hydrating nodes are born committed with the loading value so the claim matches the placeholder markup by construction — and readHydratedValue gains the inverse guard the loaded replay exposed: a settled serialized landing (s===1 stamped ref) must NOT unwrap synchronously for a loading-window node, or the client computes real-data structure during the claim walk against placeholder DOM and corrupts it (the exact mirror of the pre-strip streamed failure). It hands the async runtime a clean thenable instead — commit #0 serves through the synchronous walk, the landing applies on the following microtask, the acknowledged loaded-mode tradeoff. Parity scenarios flip from pinning the strip to pinning the design: shells now assert placeholder markup (skeltail/emptyend), settled text asserts the landing, and the update pass pins post-hydration refetch. Verified: signals 1225/1225, solid-js turbo 26/27 tasks — the one failure is solid-web's pre-existing retry-robustness timeout, reproduced identically on clean next; hydrate parity 65/65 both modes.** (ce8e46b)
- **docs+test(signals): close the audit gaps around the loading window — spec, internals, transition pins. (1) SPEC-ASYNC-SEMANTICS.md gains A27: as written, A19's definition (pending ≡ observable value not final) plus exception 1 (only *uninitialized* sources are loading-class) would have classified the open loading window as pending via cause (ii) — the spec contradicted the shipped verdict-quiet behavior. A27 rules the commit-#0 window loading-class on all three axes (reads serve commit #0, transitions never initiated/extended, verdict quiet at every distance in both forms), frames it as A19's question scoping applied (answered by declaration — re-ask-shaped, A24 family) rather than a new exception, records why true was structurally unavailable (pending is chain-shaped; no held commit to shadow; a point verdict cannot propagate without rebuilding the machinery the window silences), and notes A25 unchanged for plain seeds — seedLoadingValue is the author promoting the draft to commit #0. A19 gets a one-line cross-reference. (2) INTERNALS-ASYNC-STATE.md §1 gains the _loading row (the only node field the table was missing): set at birth, invisible to the verdict path by construction, cleared by first landing on any path, kept by real errors. (3) The one untested claim in the matrix — "the window never holds a transition" lived only in comments — is now pinned by two tests: writes concurrent with an open window commit ambiently while the identical write pair after close is transition-held (the loading-class/pending-class contrast in one test), and a loadingValue node mounted inside a live transition renders commit #0 immediately and adds nothing to what the transition waits for (its never-landing flight would deadlock the completion check if the window were pending-class). Both passed first run — pins, not fixes. 27 tests green. No changeset: docs and tests only.** (91cc527)
- **feat(signals): loadingValue / seedLoadingValue — commit #0 for async sources. A memo (createMemo / createSignal(fn) / createOptimistic(fn)) born with { loadingValue } — and a projection store (createProjection / createStore(fn) / createOptimisticStore(fn)) born with { seedLoadingValue: true } — starts committed instead of STATUS_UNINITIALIZED: the loading value (the projection's seed) is the first entry in the node's value lineage, served to every reader during the compute's first flight. handleAsync returns the committed value instead of throwing NotReadyError while the new _loading window is open, so first flights never suspend readers, trip Loading boundaries, or hold transitions (loading-class, matching boundary-fallback semantics) — while isPending on the source reads true straight off the window (newQuestionInFlight), enabling value-driven loading UIs. The window closes at the first real answer on every landing path (sync return, sync-resolved promise, first iterator yield, async settle — errors propagate but keep the window: a retry serves the placeholder again); after that, refetches use the normal pending machinery unchanged. An unready sync dependency or NotReady rejection during the window registers settle/retry bookkeeping (_pendingSources + _blocked) without read-visible status so serving continues and the flight resumes when the source settles. loadingValue is typed strictly as T (nullable placeholders require a nullable node type) and seeds the compute's first prev. Core cost: +355 B min / +99 B gzip on the tree-shaken core.** (521b73d)
- **dynamic: initialize new mounts from the latest resolved address, not the kept binding's** (e999401)
- **notes: render the New/Edit buttons on the server as plain anchors** (9846fe3)

### Fixes
- **fix(solid): hybrid async-iterable takeover for signal-shaped nodes (#2993)** (d9050a8)
- **fix(solid): lazy() settles after its async gates — the beta.33 dev-streaming livelock. With an async asset resolver (dev-server manifests), every re-creation of a lazy component across suspended render passes armed a fresh assetsPending gate even after its module and assets had settled: the per-request _lazyAssets cache memoized the resolver's PROMISE forever (each new wrap chained .then off an already-resolved promise — pending at the render memo's compute, settled one microtask later), and the moduleUrl-less path chained p.then per creation with the same geometry. A route layout's outlet re-creates its lazy child on every retry pass, so each pass threw NotReadyError on a gate that resolved immediately after and the boundary resume loop re-rendered forever on the microtask queue — timers starved, ids and serializer state grew without bound, and the dev server died on V8 heap exhaustion (~30s per request; bisected to the dx 0.50.0-next.41 bump, whose retry-wrapper flattening removed the accidental bound the old per-pass wrapper stacking imposed). Both gates now settle structurally: the cache entry upgrades to the resolved VALUE when the resolver settles, and a re-creation after the module import settled reads $$moduleUrl synchronously instead of chaining another promise hop. Regression test bounds the re-creation loop with a give-up sentinel so the pre-fix state fails as an assertion (2/2 fail pre-fix, pass post-fix) instead of hanging the suite. Verified against the fullstack template repro: /users/1 dev-streamed in 0.29s cold / 4ms warm (was 30s+ then OOM, exit 134). Full bar: turbo 27/27; all eight size gates green (server-only change).** (f14e4ec)
- **fix: loading-window commit #0 integrity — shadow drafts, parked errors, quiet landings (#2988 #2989 #2990)** (ba7560f)
- **fix: the client-source hydration gate must not close the loading window** (766ea30)
- **perf(signals,solid): size pass over the loading window — dedupe, hoist, unconditional clears; the signals gates ratchet for the feature. The unready-source parking sequence (blocked + addPendingSource + setPendingError) dedupes into parkLoadingWindow, shared by recompute's catch (sync dependency throw) and handleAsync's handleError (NotReadyError-rejected flight); recompute's catch hoists its four instanceof NotReadyError tests into one boolean; the six window-clear landing sites drop their read guards (an unconditional store to an always-present boolean slot is smaller than check-then-write and semantically identical). The hydration entry stops precomputing hasLoadingWindow per wrapper — options thread through readSerializedOrCompute into readHydratedValue, which checks at read time (hydration-only reads, trivial property probes). Measured effect is honest but small: core floor 7.19 -> 7.18 KB brotli, minimal-app 9.84 -> 9.81; the bulk of the feature's ~110 B is ~15 already-minimal sites on always-retained memo paths, and the structural outs don't exist — the window can't ride STATUS_UNINITIALIZED (born-committed flags 0 is the invariant that keeps isPending false and transitions closed) and null-slot hooks can't shake because loadingValue is an option, not an import. Per the size-config's own convention the two breached gates ratchet with the reason recorded inline: core floor 7.1 -> 7.35 KB (measured 7.18), isPending/latest 8.75 -> 9 KB (measured 8.84); createStore (12.99/13.15), minimal (9.81/10), CSR (11.96/12) hold. scripts/size/package.json records the esbuild postinstall approval newer npm requires. Also: the demo page's aria-busy takes the enumerated "true"/"false" form and the class object coerces the provisional flag to boolean (turbo's typecheck against freshly generated types caught both). Verified: turbo 26/27 (the one failure is the pre-existing retry-robustness timeout), hydrate suite 118/118 directly, all five size gates green.** (913913a)
- **test+fix(solid): the loading window survives every ssrSource mode — parity matrix, two hydration fixes, commit-#0 types, and a demo page. Six new harness scenarios extend the two existing ones into the full matrix (iterator memo, ssrSource "client" memo, hybrid iterator memo, generator projection, "client" seed store, hybrid seed store — each placeholder flips a Show branch so a window disagreement corrupts the claim structurally), and the matrix immediately caught two real bugs. (1) A fully-buffered iterator replay (loaded mode) delivers its first yield synchronously via syncThenable, closing the window mid-claim — the client computed real-data structure against placeholder markup ("expected <b> but found <i>iter-final"). normalizeIterator now defers the first yield one microtask when the node has a loading window; sync delivery stays for windowless nodes, whose claim NEEDS the value. (2) The buffered store replay applied the first-yield snapshot synchronously at claim — right for windowless stores (the snapshot IS what the SSR DOM shows), wrong for a seed window (the DOM shows the SEED): after the rebase onto next picked up the backlog-parking fix (a37611e7), the snapshot now parks with the backlog until hydration completes, closing the "emptyiter-bend" partial-claim corruption. The hybrid seed-store scenario also documents a pre-existing hybrid constraint: promise-shaped takeover derives hand values back by RETURNING them — draft mutations on the takeover run go to the discarded shadow draft — and with the deferred serialized adoption superseded by the takeover flight, the takeover landing is what closes the window. Types learn commit #0: loadingValue overloads on createMemo/createSignal/createOptimistic in both runtimes drop undefined from the accessor — including ssrSource "client", where the server now flushes the loading value and the client serves it pre-compute — and type prev as T, matching the signals core; the client-mode scenario drops its cast to pin the inference. The rendering example gains a Skeleton page (lazy route) demoing the basic pattern: value-channel skeleton on first flight (no Loading boundary on the page), isPending-driven dim on refetch, fresh window per client navigation; verified live against the streaming dev server — the shell flushes the skeleton markup and the post-</html> chunk is a single settle script carrying the landing as data. Verified: turbo 26/27 (the one failure is the pre-existing retry-robustness timeout on next), parity 79/79 both modes, solid-web test-types green, example typecheck green.** (c320429)
- **fix(solid): hydration drops the loading window — loadingValue/seedLoadingValue are stripped by the hydration-aware wrappers until SSR renders commit #0. The server ignores loading values today (an async source suspends into its Loading boundary and streams the REAL value), so a node hydrating with an open loading window computes structure from the placeholder while claiming DOM the server rendered from real data — a Show over data.skeleton claims the wrong branch and corrupts the walk (pinned: the parity harness's streamed replay produced exactly this against the un-stripped build — "Hydration tag mismatch: expected <i> but found <b>item-0" — before the guard went in). The strip (stripLoadingValue, applied in hydratedCreateMemo/Signal/Optimistic and the store-like wrappers) makes a hydrating node adopt the serialized server value exactly like any async source; loading values apply only to fresh client mounts, where commit #0 is correct by construction — server HTML and hydrating client then agree by construction in both replay modes. Two parity scenarios pin it (loading-value-memo, loading-seed-store), each shaped so the placeholder flips a Show branch: a regression corrupts the claim rather than merely mismatching text, and both run in loaded and streamed modes with the harness's generic invariants (no warnings, no client-created nodes, node identity, update pass). Verified: solid-js 502/502, solid-web client 404/404, hydrate 101/101 (65 parity), server 240/241 — the one failure is retry-robustness's "root hole (no boundary)" timeout, reproduced identically on clean next (pre-existing, tracked separately). The real SSR story for the feature (server renders commit #0 into HTML, keeps streaming the landing as data, hybrid collapse) is the agreed follow-up that replaces this guard.** (103e57f)
- **fix(signals): dev error for untracked async reads after await (#2987)** (b37d19a)
- **fix(web): include cookie declarations in package (#2985)** (3740fde)
- **perf(solid): the store engine shakes out of hydrating bundles that never import a store primitive — enableHydration() installed a dedicated hydrated implementation per store-family primitive (hydratedCreateStore/OptimisticStore/Projection/Optimistic), statically retaining the engine (store, reconcile, projection, optimistic in @solidjs/signals, ~7 KB) in every bundle that calls hydrate(); the signal- and store-shaped hydration bodies are now generic adapters parameterized by the core implementation (_hydrateSignalLike/_hydrateStoreLike — hydratedCreateSignal/Memo share them too), installed by enableHydration() while each wrapper passes its own core primitive in, so the engine rides the import an app already needs to use stores and there is no state where a hydrating store call can miss its adapter (sharedConfig.hydrating can only be true after installation — the same invariant lazy()'s _lazyHydrationLookup rides); the buffered store-replay backlog parking (a37611e7), normalizeIterator conflation (23657d29), and truncation sweep (d7f95bbc) are reached unchanged — only how the code is reached moved; new hydrating size-scenario pair locks it in: no-store 22.60 -> 15.83 KB brotli measured (ceiling 16.15), with every store family 22.62 (parity with pre-seam 22.68, ceiling 23.05), CSR 11.75 / minimal 9.61 unchanged within noise** (28f7bec)
- **perf(solid,web): hydration-phase seams shake out of CSR bundles — isHydrationInProgress/onHydrationEnd move from the sharedConfig literal into enableHydration() (the null-slot pattern every other hydration hook follows), so the phase bookkeeping they close over (_pendingBoundaries, _hydrationDone, the callback list) no longer ships in pure-CSR builds; both fields were already optional and @internal, consumers treat absence as not-hydrating (refresh optional-chains, clientOnly falls back to the bare queueMicrotask that onHydrationEnd itself used outside hydration) — −100 B brotli on the CSR size scenario (11.72 measured), −80 B on the minimal-app floor (9.61), CSR ceiling ratcheted 12 -> 11.95 KB** (8923ac6)
- **fix(solid): buffered store-shaped async-iterable replay defers its patch backlog past the hydration claim pass — hydrateStoreFromAsyncIterable applied synchronously-buffered patches inside the very pull the claim pass triggers (Repeat reading the projection's length drives it), and since projection draft writes stage in the override layer until the firewall commits, write-time snapshot capture recorded the still-uncommitted seed (not the first-yield state the SSR DOM shows) as the pre-write base, so any claim pass after the batch hydrated against pre-stream state, claimed nothing, and rebuilt every row fresh beside the orphaned server-rendered row; the backlog now parks until hydration completes (onHydrationEnd — a plain microtask when it already has), exactly where a live stream's yields land, so claiming sees the SSR snapshot and reuses server rows; conflated single-update semantics unchanged — every sync-available patch still applies in order within one pull and observers see one update to final state, live post-hydration yields still one at a time; covered by a parity scenario (projection-repeat-stream), a DOM-level node-identity spec (buffered / partial-buffered / live), and store-replay unit tests for the deferred backlog** (a37611e)
- **fix(solid): truncation sweep covers every pending registry ref, not just _fr declarations — a dropped stream also strands the registry's plain serialized promises (owner-id computation values, library-keyed data refs like the router's query channel) as never-settling, hanging any consumer that adopted one; at DOMContentLoaded every still-pending seroval resolver is dead (settle scripts execute during parse), so the sweep now walks the cross-reference scope (self.$R) and answers per consumption state: promises already claimed one-shot out of the registry (the router deletes its key on load) reject through their resolver — the bare promise is the only channel left to that consumer and its .then chain handles errors — while entries still registered are deleted so future presence checks fall through to a fresh compute/fetch; rejecting the registered ones raw would land an unhandled error inside live owner-id adopters no boundary can route and halt the reactive system, which is also why the sweep runs a macrotask after the fragment pass (boundary teardown disposes its hydration-time adopters first)** (d7f95bb)
- **fix(solid): buffered async-iterable replay keeps the latest yield for signal-shaped hydration — normalizeIterator's greedy batching loop advanced `latest` unconditionally, so a stream that completed (or advanced several resolutions) before client hydration began — whose done result seroval buffers synchronously right behind the data — returned `{ done: true }` from the batch and discarded every yield after the first, pinning hydrated createMemo/createSignal(fn)/createOptimistic to the first resolution while the store replay path applied all buffered yields correctly under identical conditions; the loop now tracks the last data yield separately (the store path's `if (!r.done)` guard, mirrored), delivers it as the batch's value, and hands the done result to the following pull — replay semantics otherwise unchanged: buffered backlog conflates to its latest yield in one visible update (the same final state the store path's batched patches produce), live post-hydration yields still apply one at a time** (23657d2)
- **fix(web): production server bundles strip _DX_DEV_ — the main server target (dist/server.js/.cjs, the only node/worker/deno artifact) built without replaceDev(false), and babel constant-folds the unreplaced truthy "_DX_DEV_" literal, so the artifact permanently took the dev branch of every gate: the committed-stub header guard threw instead of console.error + no-op, turning a late header write from async SSR work into a crashed production request (#2982); frames/dist/server had the same omission (dev useHead/insert warnings shipped in prod); guarded behaviorally by a new dist-artifact spec importing dist/server.js directly, since the folding erases the marker and defeats any string scan** (57611e8)
- **fix(signals): disposed computations leave the scheduler heaps unconditionally — disposeChildren's child walk only deleted queued children from the heap inside its `_deps` branch, so a dependency-free computation queued by refresh() stayed queued past disposal and the next flush recomputed it, recompute()'s _flags rewrite clearing REACTIVE_DISPOSED and resurrecting the node (post-unmount runs, readable accessor, leaked cleanups, #2983); heap removal is now gated on the heap flags alone (matching markDisposal), and the standalone dispose() path removes the node itself from its heap, mirroring unobserved** (aa5b96e)
- **fix(web): httpHeader/httpStatus retract by declaration, not by snapshot — the write-time whole-field snapshot restore was only correct for LIFO disposal, so an earlier sibling scope recovering while a later writer stayed live deleted the survivor's contribution (dropping surviving Set-Cookie entries and headers, #2984); each response head now keeps a per-header (and status) ledger of live declarations, and retraction removes exactly one entry and replays the survivors over the integration's base in original write order, entry-exact for set-cookie** (38a8b51)
- **fix(solid): SSR retry robustness — lazy() memoizes resolveAssets per moduleUrl per request (component re-creation across suspended passes re-asked the manifest every time, multiplying dev-resolver work by retry count), finalizeError routes handler-less boundary errors through the renderer's failRender seam and ssrHandleError guards the ownerless retry path, so a real error in a retry pass fails the request instead of crashing the process; regression coverage in solid-web's server suite (counting resolver, 6000-deep re-suspension, root-hole and boundary-resume error containment)** (af1c71e)
- **fix(web): resolve the wire layer's lazy codec import to the serialization entry — the runtime late-loads seroval behind a dynamic import (JSON fast path answers plain-data calls without it), and the single-file dists externalize that import to @solidjs/web/serialization so app bundlers split the codec into a lazy chunk against the same instance plugins are authored with** (da5646b)
- **fix(web): RequestEventLocals reaches the entry as a real re-export so augmentation identity can't drift** (a8d56dc)
- **fix(frames): drain records when a fragment reveals into an adopted region (#2979)** (80970b7)
- **fix(frames): re-arm the shell gate on an address switch so isPending holds until the new call answers (#2977)** (8e148a8)
- **fix(web): httpHeader retraction keeps multiple Set-Cookie entries exact** (c6e0063)
- **fix(frames): document adoption claims its region's deferred fragments (#2978)** (af97611)
- **fix(server): evaluate allocation-capable prop getters at client-matched slots (#2976)** (dc7b5c2)
- **fix(web): shell-gate fresh server-component mounts on first apply** (d657df1)
- **fix(web): dispose stream-mounted slot fills at occurrence unmount** (c85b610)
- **fix(examples/notes): carry the search filter through in-app links** (482f7fa)
- **fix(frames): hand slot claims over from the enclosing hydration registry** (4fec66b)

### Backend
- **Version packages for 2.0.0-rc.0** (ff4d3c4)
- **Version packages for 2.0.0-beta.34** (4816a4f)
- **Update dom-expressions to 0.50.0-next.42** (57194d8)
- **Merge branch 'next' of https://github.com/solidjs/solid into next** (4879891)
- **Version packages for 2.0.0-beta.33** (09b3c23)
- **Update dom-expressions to 0.50.0-next.41** (3b97432)
- **examples: vite-plugin-solid next.24 — turnkey options move to `start: {}`, compiler override drops** (8d9bd0a)
- **test-types: the chat-shape spec satisfies nodenext resolution (explicit .js extension, untyped slot props record)** (5658893)
- **tests: adopted-fill fallback residue, onSettled after hydration, inline-projection latching** (f3d1764)
- **chat example: Stage 5 usage projection, server-side highlighting, partial-stream smoothing** (560cbce)
- **Container tier (DR-2 case 3): projection traces across the slot border** (f3accb3)
- **serialization/decode entry: lazy readers load half the codec** (45ef757)
- **Frames client size pass: lazy seroval codec, sc:live op-log compaction** (2722022)
- **chat example: idiomatic slot args — live expressions on both faces** (1ccb112)
- **Document-face live slot args, client half: fid-gated slot ops + matrix rows** (dd163c5)
- **chat example: t=0 welcome reply — the Stage 4 showcase** (966222b)
- **Document-face live holes (Stage 4): scope barrier reads, the sc:live client pump, t=0 matrix rows** (3bcce84)
- **matrix: rows for live markup holes (Stage 3) — marking, ledger, morph, lifetime, attr cells** (bf41b74)
- **Live markup holes, Solid server half: creation stamps, boundary skip tags, response holds** (09e2d3b)
- **docs(example)+test: the Skeleton demo page gains the store half — createStore + seedLoadingValue renders beside the createMemo + loadingValue card, sharing one Refetch and one isPending dim (memo pending OR store-read pending), so both commit-#0 forms are visible in initial SSR and on client navigation. Verified live against the streaming dev server: the shell flushes both skeleton cards (8 skeleton lines, two aria-busy), both landings travel as serialized data only. The seedLoadingValue casts in the parity scenarios were stale, not load-bearing — ProjectionOptions (client) and ServerSsrOptions (server) both type the flag now — so all four drop; the remaining casts are the async-generator computes. solid-web test-types and example typecheck green.** (9a5977e)
- **Version packages for 2.0.0-beta.32** (3194631)
- **Update dom-expressions to 0.50.0-next.40** (1c03436)
- **web: freeze-pass exports — serialization plugin authoring, RequestEventLocals, commitEventResponse** (0813a51)
- **Matrix: the address-switch dimension gets its two missing cells** (c2cdc82)
- **examples(chat): slots render as JSX, never as calls** (c13990a)
- **examples: vite-plugin-solid next.22 (drops the _$SC head splice); NoteEditor reads initial props under untrack** (727ce1b)
- **changesets: DR-1/DR-2 entries are patches — beta pre-release, no minor bumps** (d0bf623)
- **Merge feat/wait-asset-seam: waitAsset rxcore seam for client CSS reveal gating** (75862c1)
- **web: implement the waitAsset rxcore seam (client CSS reveal gating)** (bef6da9)
- **rxcore ssrAsyncValue + document-face arg-tier coverage (DR-2 value tier, t=0)** (202acdd)
- **changeset: value-tier note leans on the shell gate that shipped separately on next** (eec7638)
- **server signals: memo liveness for the binding ledger (DR-2 case 1)** (3fd0499)
- **examples/chat: simulated LLM chat on server components (DR-2 showcase)** (30a932a)
- **DR-2 value tier: asyncArg border typing + async-iterable slot arg coverage** (b160a5f)
- **DR-2 value tier (client half): async slot args suspend at the consumption read** (311cc4e)
- **ssrHandleError probe mode: root async head props hold the shell (#2975 follow-up)** (b6071ba)
- **web: cover useHead pending props under Loading on the client** (163fcef)
- **server: mark Loading discovery passes so useHead suspends on pending props (#2975)** (2a25fd4)
- **signals: tolerate bare IteratorResult steps in async-iterable reads (for-await semantics)** (1313447)
- **web: RC API-freeze pass — rich-args entry, build-variant error gate, drop renderToStringAsync, surface markings** (595b9e9)
- **web: overload createSSRResponse's mock to match the runtime signature** (50923e9)
- **web: expose the response-head lifecycle on the isomorphic surface** (7f9de5f)
- **Document the response-head lifecycle, composeMiddleware, and the wrapInvocation seam** (687a993)
- **Version packages for 2.0.0-beta.31** (b25c797)
- **Update dom-expressions to 0.50.0-next.37** (ce60796)
- **Drop the types re-run from web's test-types: it raced example typechecks** (eafce88)
- **Pin adopted claim scoping on an args-bearing call (#2973)** (4b747d3)
- **Adopted claims derive their prefix from the wire id, not the call address** (977b176)
- **Update dom-expressions to 0.50.0-next.36; recordsPending answers record arrival, not hydration completion** (3ba6c86)
- **Sync results never serialize: the code is the value transport** (8e7c1d0)
- **Merge pull request #2970 from jer3m01/chore/type** (8e1ceec)
- **Forward store options to the server projection so ssrSource works on stores** (a60b288)
- **Replay lane-gated readers at ambient commit so isPending can't swallow a write** (0cd35f0)
- **One reveal owner: the fragment ledger replaces claim sets and page scans** (40b05e1)
- **Adopt the server-component identity split in dynamic and the frames client** (bcbe7e5)
- **Type the record-race seam version-tolerantly** (c5f2ca8)
- **Wire the adopt-time record-race seam and make the document record drain re-drainable (#2968)** (38e2e72)
- **Merge PR #2967: keep late-arriving boundaries claimable, slot ranges live** (4efa346)
- **Keep a late-arriving server-component boundary claimable and its slot range live** (70d0da6)
- **Arm clientOnly's swap without an owner so sibling hydration ids stay aligned** (edb3e36)
- **Version packages for 2.0.0-beta.30** (2bb02e0)
- **Own streamed-fragment reveal policy in the hydration runtime (_$HY.f)** (40af691)
- **Claim late-arriving fragments after hydration completes (#2964)** (51f971b)
- **signals: drop unused REACTIVE_ZOMBIE imports in core.ts and optimistic.ts** (0342641)
- **Cancel zombie recomputes queued by a parking transition's own writes** (4ac3aa8)
- **clientOnly: emit early preload hints from the compiler-injected module URL** (8c8b591)
- **Merge origin/next: drop the temporary vite-plugin-solid link override** (051b58b)
- **frames: live slot props — args changes update the mounted binding instead of re-creating it** (4533813)
- **Merge PR #2961: hand slot claims over from the enclosing hydration registry** (c94fc5f)
- **examples: adopt released @solidjs/router 2.0.0-next.13** (5ea0d57)
- **Hand off dynamic's live mount when a server component changes arguments** (9cbdb85)
- **drop the temporary vite-plugin-solid link override; pin published 3.0.0-next.21** (0204ce4)
- **examples: adopt released vite-plugin-solid 3.0.0-next.21; drop the local link override** (5dfb126)
- **Version packages for 2.0.0-beta.29; stop versioning the example apps** (4bc0be0)
- **Merge web-hoists: clientOnly + httpStatus/httpHeader hoists, RFC 10 decision record** (abfe23a)
- **web: align clientOnly's fallback hydration ids; keep the manual gate** (b323482)
- **web: start clientOnly's lazy import exactly once across instances** (46c9f37)
- **frames: adopt per-args boundary identity from @dom-expressions/runtime 0.50.0-next.34** (5a44856)
- **bump dom-expressions to 0.50.0-next.34** (4c7aa46)

### Tests
- **test(web): cast the retry-robustness raw-hole children past JSX.Element — the bare function IS the surface under test (a component wrapper would reroute through createComponent) and Element excludes callables by design; casts are erased, runtime unchanged** (a1a6ec9)
- **test(signals): treeshake guard names the verdict->optimistic coupling and asserts the dist artifact — the isPending fixture now asserts POSITIVELY that verdict brings the optimistic engine (by design: companion flips are optimistic writes, #2887), and new dist/prod fixtures assert the packaging introduces no coupling beyond src (the guard was previously blind to anything the build could add)** (a205730)
- **test(web): annotate the sibling-walk cursor to break the TS7022 inference cycle** (79f1f30)
- **test(web): pin the thrown-Response control-flow invariants ahead of the freeze** (58f70db)
- **test(web): pin isPending over the navigation source during a CSS-gated hold** (d66d19f)
- **test(web): make the transition-hold assertions explicit in the gating spec** (c371da4)
- **test(web): CSS reveal gating end-to-end through the real core** (32d8d0d)
- **test: probe the document face x DR-2 arg tiers (t=0)** (377f000)
- **test(web): flip the error-release matrix pair to passing — this branch links the runtime with error-apply** (4704cca)
- **test(web): server-component lifecycle matrix — systematic mount/response/slot/arg/state/cleanup/reveal coverage** (f18253f)
- **test: hydration parity scenarios for the httpStatus/httpHeader primitives** (9a21ab3)

### Docs
- **docs: README for the chat example — three tiers of liveness, one border** (97a6279)
- **docs: loadingValue/seedLoadingValue as declared first paint (advanced)** (b256f1e)
- **docs(example): the Skeleton page renders the origin pattern — default data through the real template, not a skeleton costume. Gray shimmer rows still read as a fallback; per the critique that spawned the feature ("show the UI with default data with a loading indicator", "use the real graph component as the loading skeleton but with dummy data"), the loading value is now dummy items with the real items' shape and sentence structure (Shipped release #—), rendered by the same FeedCard with normal typography, and the affordance is encoded in the data itself: a provisional flag drives dimmed text and an inline pulsing dot, nothing structural. Verified via streaming SSR: dummy items and provisional classes in the shell, the landing rides the data channel only.** (34692c5)
- **docs(example): the Skeleton page stops impersonating a Loading boundary — no Show, no fallback tree. The loading value is now data shaped like the answer (a feed whose items haven't arrived: placeholder rows with empty text), rendered by the exact same FeedCard/For template as the landed data; CSS paints rows with the placeholder flag as shimmering blocks. This is the pattern the feature exists for — commit #0 flows through the value channel and the one template, instead of hand-rolling the branch-to-a-fake-tree shape that Loading already does better. Verified via streaming SSR: shell carries both aria-busy cards with placeholder rows, landings ride the data channel only.** (e1412bc)
- **docs(signals,solid): the `transparent` effect option is typed, documented public API — the runtime has always honored it on createEffect/createRenderEffect (invisible to the hydration id scheme: inherits the parent id, consumes no child slot; computes live during hydration instead of adopting the serialized server value) but the flag was absent from the published EffectOptions type (typed only on MemoOptions) and documented nowhere, so the first-party router ships `{ transparent: true } as {}` casts on its client-only link-state and scroll-restoration effects (the hydration-surface audit's "cheapest real fix"); it is the pattern-level replacement for branching on hydration state — which freezes the first run's decision, the frozen-decision class that bit TanStack's Matches — so it is now documented as such on both option types, in the solid-js client wrapper docs, and in RFC 05's SSR/hydration section, with type-level tests and a hydrated-effect runtime pair (transparent runs live and consumes no id slot; non-transparent adopts the serialized value at its id); SSR ignores the flag (server-side nodes always allocate their id slot) so the docs scope it to nodes the server does not create; types+docs+tests only — all seven size scenarios byte-identical (9.61 / 11.75 / 15.83 / 22.62 unchanged)** (ab5f83c)
- **docs(web): sessions are app-layer by final ruling — recipe over @remix-run/cookie, first-party primitive retired** (f837fc0)
- **docs(frames): slots with args render as JSX everywhere authored code is modeled** (43b5aaf)
- **docs(rfc-12): cookies are the codec + native Headers — the final C6 ruling** (eee9c29)
- **docs(rfc-12): cookie helpers (C6) and the sessions recipe** (7e198b7)
- **docs(rfc-11): record the derivation pass — identity split, async slot-arg classification** (cb32e40)
- **docs: mark the serialization subpath as internal plumbing, not public API** (94e55fd)
- **docs: add RFC 12 (SSR and the HTTP exchange); cross-link and index the new web surface** (413dcc4)
- **docs: document clientOnly with control flow and ssrSource/deferStream with async data** (d4ecfd4)

### Chore
- **chore: adopt @solidjs/vite-plugin (renamed from vite-plugin-solid)** (55570dc)
- **refactor(solid): dedup the pre-hydration gate lifecycle into withHydrationGate** (667a020)
- **chore: ignore chat-example in changesets like the other example apps** (4624bcb)
- **chore: root vite-plugin-solid to next.24 — the compiler-pin half the override drop assumed** (dbeec8d)
- **chore(size): the hydrating gates ratchet for the loading window, measured on the rebased base. With the store-engine seam's new hydrating scenarios (28f7bec2) now measuring the feature's hydration guards for the first time: no-store 16.15 -> 16.35 KB (measured 16.04, +210 B over the seam landing — the core window plus the claim-walk guards on the shared signal-hydration body: the clean-thenable unwrap guard, the deferred first yield, the hasLoadingWindow probe), with-stores 23.05 -> 23.3 KB (measured 22.83, same bytes plus the store-replay seed parking); reasons recorded inline per convention. Full picture against clean next: core floor +110 B, createStore +120, isPending +140, minimal +130, hydrating +210/+210, CSR +90 — all seven gates green. Verified on the rebased base: turbo 26/27 (pre-existing retry-robustness timeout only), server 245/246, hydrate 118/118.** (9d3a1d5)
- **refactor(signals): the loading window is verdict-quiet — isPending stays false through a loadingValue node's first flight. The previous commit read true straight off the open window, but that verdict was a point anomaly: it existed only at the probed node while reading false both upstream (dependencies) and downstream (derived memos hold real committed answers computed from commit #0, and nothing propagates by loading-class design) — and pending has always been derivative, so a verdict that cannot propagate is not a smaller pending, and making it propagate would reintroduce exactly the status machinery the window exists to silence. Quiet also restores isPending's correlation with transition-class machinery (first-flight work is loading-class and never holds transitions) and keeps server (always false) and client hydration trivially consistent with zero special-casing. Semantically the window joins the existing quiet class alongside reask: the shown answer still answers the question — commit #0 answers by declaration, first-load affordances live in the value channel (null / skeleton provenance the author encodes), and isPending remains refetch truth for an answered question, so `data.skeleton || isPending(data)` covers the two disjoint states. Mechanically this DELETES the runtime special case (newQuestionInFlight reverts to baseline; the invariants carve-out goes too): the verdict path no longer knows _loading exists — 19 B min / 7 B gzip smaller, core delta vs next now +391 B min / +128 B gzip. Refetch-window assertions (post-landing) are unchanged and still read true.** (ec4b672)
- **ci(size): run the size gate on direct pushes to next, not just PRs** (1609722)
- **chore(size): raise the +createStore budget to 13.15 KB** (be8ec71)
- **chore: point the runtime link at the main dom-expressions checkout** (609a26a)
- **chore: update component types to accept ref array** (15b512f)
- **chore: update dom-expressions to 0.50.0-next.35 and drop the runtime link override** (c3fa949)

_Recap by [Repo Wrapped](https://repowrapped.com/gh/solidjs/solid?utm_source=github-action)._