Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7982c1a
fix(solid): a claim reads the trace's snapshot; the backlog lands aft…
ryansolid Oct 6, 2026
3aeba4e
feat(solid,web/frames): an adopted occurrence claims through the hydr…
ryansolid Oct 6, 2026
092b40b
docs(server-components): consistency contract — C1's mechanism is the…
ryansolid Oct 6, 2026
433a874
docs(server-components): record the 2026-10-06 rulings on A2b — the p…
ryansolid Oct 6, 2026
a5472d7
fix(web/frames): A1b + A4 S-ref — refs settle at the write through th…
ryansolid Oct 6, 2026
193be50
fix(web/frames): A4 S-record — the document declares a slot record at…
ryansolid Oct 6, 2026
964dc35
docs(server-components): frames rulings — 1.2/1.3's carriers and the …
ryansolid Oct 6, 2026
40dfa26
fix(web/frames): A7 — a frame's error is an errored async value: the …
ryansolid Oct 6, 2026
9ec2e6c
fix(web/frames): A7 — the re-ask mints its callable through the late-…
ryansolid Oct 6, 2026
87e5827
fix(web/frames): A3 — a reveal applies its range; R.reveal's readines…
ryansolid Oct 6, 2026
7713f51
docs(server-components): frames rulings — 3.3's outward face landed (…
ryansolid Oct 6, 2026
1cb5b1a
test(web): pin the adopted face of frames-rulings 3.3 — an sc:live er…
ryansolid Oct 6, 2026
9c5875b
frames: A5′ — fragment ownership by rendering, G9 collapse, claimRegi…
ryansolid Oct 6, 2026
79d6996
docs(server-components): A5′ landed — rulings 3.3 claimant by renderi…
ryansolid Oct 6, 2026
de972bd
frames: one sweep is one chunk — the `ops` member (C13)
ryansolid Oct 6, 2026
4b5350c
frames: the plain response's streaming bound — `complete.bound`
ryansolid Oct 6, 2026
c73f20f
frames: a server <Loading>'s post-flush failure renders its outcome (…
ryansolid Oct 6, 2026
0e38a57
docs(server-components): frames rulings — the server half built (A6),…
ryansolid Oct 6, 2026
6cf0809
frames: the A6 client half, trimmed (−56 B min)
ryansolid Oct 6, 2026
dbb3237
test(hydration): generic hydration consistency pins and harness arm
ryansolid Oct 6, 2026
ca76d9a
size: raise hydrating caps (maintainer Size-Exception); frames/page c…
ryansolid Oct 6, 2026
f171325
docs(server-components): Phase A gate taken — reds green / unrepresen…
ryansolid Oct 6, 2026
0aab932
test(server): the generic-hydration artifact renders on a fake clock …
ryansolid Oct 6, 2026
1793a2a
Merge branch 'next' into wip/frames-pass-integration-2
ryansolid Oct 7, 2026
9914189
size: re-derive the hydrating caps after merging next (#3849)
ryansolid Oct 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/container-trace-claim-reads-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"solid-js": patch
---

A fill that claims adopted markup reads the state the server rendered it from (frames-rulings 3.6 (iii), "the consumer parks" — S1's third commit ported onto `next` without its `claiming` hint).

- `materializeContainerTrace` parks a replayed backlog beyond the snapshot until hydration ends (`onHydrationEnd`; the next microtask when no hydration is in progress) and then applies it as one ordinary update. A container trace is materialized at a fill's arg-read; when that fill claims server markup — the document's pass, a frame's deferred claim under its hold, a claim at a fragment's reveal after hydration-done — the snapshot is what the markup was rendered from, the claim trusts the markup (a text hole is never rewritten during a claim), and a store already past the markup left the DOM diverged for good. Parked, the claim reads the snapshot and the backlog lands after it, so the DOM catches up outside hydration. The release order is the one 3.2 pins: the claim, the frame's hold release, done, then the backlog. A fresh mount pays one beat for not being told apart: its backlog lands a microtask after its snapshot, before any paint. A failure in the backlog applies in order, after the parked patches.
- The materializer creates its projection under a DETACHED root. Rooted under the reading owner — during hydration an id-carrying one — a trace revived at t=0 consumed one child id per trace while one revived by a late claim consumed none, and a keyed sibling after the frame hydrated under different keys in the two runs.
5 changes: 5 additions & 0 deletions .changeset/frames-a1b-stage-deletion-s-ref.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

frames: A1b + A4 (S-ref) — a slot record's `{$ref}`s settle at the host's write, through the response's own data table (`FrameHostOptions.resolve(ref, frameId, version, current)`); an undelivered key is a pending read the response's `data` chunk settles and its `complete`/`error` rejects (L1 — a value that never comes is an error, not a silence); a fresh mount waits for the record to settle, a mounted occurrence's prop pends and holds its value. Codec data tables are per response (keyed by frame id and version). Deleted: `ServerComponentHandlerOptions.onStream`, `STAGED_DATA` and the staged tables, `FrameHost.resolve`, `FrameHostOptions.isContainer`/`FrameHost.isContainer`, `Frame.rebase`, the frame's record dedupe (`#refArgsUnchanged`, `#slotResolvedRefs`) — a re-sent record's equality is the fill's per-prop memo's — and the frame's error/root value latches (applied state keyed by record identity). `FrameHost.preview`/`Frame.preview` lose their `resolve` parameter and stay: the compute-half preview is what stages a refetch's args with the transaction that read it.
5 changes: 5 additions & 0 deletions .changeset/frames-a3-reveal-applies-its-range.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

frames: a reveal applies its range (frames-rulings 2.3, A3). A revealed segment's content is applied against the store as it is revealed — its fills mount and the segments whose placeholders it carries reveal inside it, in the same flush and before a reconstructed boundary commits the content — so the frame's flush no longer retries over its segments, and a segment nested in content a pending fill holds no longer waits for a chunk that never comes. The readiness/retry model's second ledger (`#revealed` / `#fallbackShown`) is gone: a reveal's applied state is the content record it applied, a fallback's the gate it materialized, by identity, in the one applied map; whether a segment is shown is the DOM's to say. `Frame.isRevealed(segment)` is removed.
5 changes: 5 additions & 0 deletions .changeset/frames-a4-declared-slot-records.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

frames: A4 (S-record) — the document face declares a slot record at its marker: `_$HY.r["sc:slot:<fid>:<occurrence>"]` is a pending promise written with the occurrence's markup and settled with the args by the record's data script (the shape a fragment's `<key>_fr` takes), so the adopting client awaits a record that trails its range's reveal through the value's own `.then` instead of polling the registry (C2 (a2) flips). Output shape: ≈ +32–38 B per document slot record (the resolver helpers are shared with the page's fragment declarations); a sync render (`renderToString`) writes the settled value as before. Deleted: the #2968 `setTimeout` re-drain poll and `FrameOptions.recordsPending` / `FrameOptions.drainRecords`.
10 changes: 10 additions & 0 deletions .changeset/frames-a5-fragment-ownership-by-rendering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"solid-js": patch
"@solidjs/web": patch
---

Frames A5′ — a deferred fragment's placeholder inside a server component's element is the frame's content by rendering, not by adoption (frames-rulings 3.3, ruled 2026-10-06).

**`solid-js`:** the document fragment ledger's `fragmentPolicy` lets a post-done swap proceed when the fragment is owned — its `pl-*` template is in the document and the integration's ownership predicate `_$HY.fa(placeholder)` says so — beside the existing claimant case; no hold, no replay for owned fragments. `_$HY.fr.claim` / `_$HY.fr.release` are removed from the published ledger (`_$HY.fr` is `{ pending, subscribe }`); `_$HY.fa(placeholder): boolean` is the new integration hook. `fragmentPending` now reads a revealed fragment from its swap record (`_$HY.v`) before its `_fr` stamp: the producer emits the swap script and then the `_fr` settle in the same batch, so a `_$HY.fr.pending()` read inside the reveal notification saw the revealing fragment as still pending — a page's last reveal never read as exhaustion and a waiter released on exhaustion waited forever.

**`@solidjs/web` (frames client):** installs `_$HY.fa` once (`pl.closest("[data-fid]")`, minus elements of a boundary disposed in place — C14); deletes `claimRegionFragments`, the per-adoption claim set, the cascade's claim half and the release loop (the dev-only rejection report over the region's `pl-*` templates stays, 0 prod bytes); `documentBoundary` pends on the intercept's one arrival answer (`awaitBoundary`) and `boundaryWaiters` is deleted (G9). A post-done swap into server-component markup no client has adopted yet now lands at once; the adoption that follows finds it in place and reads its declared records synchronously.
5 changes: 5 additions & 0 deletions .changeset/frames-a7-error-throws-reset-reasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

frames: a frame's error is an errored async value (frames-rulings 3.3, A7). `FrameHost.landing(address)` rejects with the error record at the response's `:error` write, so the mount's content node throws to the nearest client `<Errored>` — the covering `<Loading>` no longer releases over an empty `<solid-frame>`. An error after the landing (a later yield failing, a cut-off stream, a refetch's response erroring) errors the node the same way; with no client `<Errored>` the core halts, as for any uncaught async error. The `<Errored>`'s `reset` re-asks: an errored landing is not a landing for a fresh consumer, and the re-read opens a new flight for the same address — the handler records the call behind every address it handles or the document answered (`callFor`, `@internal`), and the client re-invokes it through the server-function registry's RPC seam, whose client half now carries `createServerReference(id)`. A response for an address whose mounts show an error writes through instead of being staged. `frame.error` still records the error.
6 changes: 6 additions & 0 deletions .changeset/frames-c12-fragment-error-outcome.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"solid-js": patch
"@solidjs/web": patch
---

A server `<Loading>` inside a server component that fails after the first flush renders the server's outcome into its fragment instead of a blank (C12 (c), frames-rulings 3.3): the nearest server `<Errored>`'s fallback for the error, at the `<Loading>`'s position (asked through the boundary error handler's new `outcome` mode; a `<Loading>` between passes the question up); with no server `<Errored>` the error escapes the component — the frame's own `:error` on the stream face (an unkeyed `error` chunk), a frame-addressed `{ type: "error", fid, error }` op on the document face's `sc:live` channel (only the owning adopted boundary applies it) — and the position keeps the boundary's own fallback. `_fr` still rejects and the keyed error chunk still rides (the diagnostics). Outside a server component nothing changes (the blank the client twin renders fresh over). `HydrationContext.registerFragment`'s resolver gains a third argument (`escaped?: { frame?: string }`) and the context an internal `frameId`.
5 changes: 5 additions & 0 deletions .changeset/frames-c13-sweep-ops-chunk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

frames: one server sweep lands as one frame (C13). The sink collects the `hole` / `attr` re-emissions one sweep produces and emits them as one `{ type: "ops", ops: [...] }` chunk on the stream face (one wire line) and one `sc:live` op of the same shape on the document face; a sweep that changes one binding emits that member alone, as before. The client maps the unit to one record map and applies it as one write — one hole pass, one `frame:applied` (the hole pass now announces once per flush, not once per hole). The document op log flattens a unit into its members (last value per hole). Additive wire (`FrameChunk` gains the `ops` member; RFC addendum in `frame-streams-rfc.md`).
10 changes: 10 additions & 0 deletions .changeset/frames-claim-through-hydrate-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"solid-js": patch
"@solidjs/web": patch
---

An adopted frame occurrence claims its server markup by re-entering hydration the way a streamed `<Loading>` resume does (frames-rulings 3.1 / 3.2, the savings plan's A2 — S-hold's window form).

- `solid-js`: `hydrateWindow(id, fn, scope?)` is factored out of a streamed boundary's resume and reached as `sharedConfig.hydrateWindow` (`@internal`): the keys under `id` gathered into the registry (the captured `scope` pair when another `hydrate()` root replaced the live one, #2917), hydrating on for the synchronous window, the current owner the claim owner (a render the window forces elsewhere is a client render, #3504), the owner the window's snapshot and live scope when none is open — so a write during a late claim is held and replays once the claim is over, and a late claim no longer re-marks the root's scope. `sharedConfig.claimRoots` (`@internal`) is typed: the claimant declares a range that may be detached around its window. `holdBoundary` stays the registration; the resume path is unchanged in behaviour.
- `@solidjs/web` (frames): `claimRender` is the window — one `createOwner({ id: prefix })` and the call — instead of a registry of its own gathered by walking the range, a hydrating flag flipped through `sharedConfig`'s setter (which reset hydration-done and re-ran its completion from outside the runtime), and a hand-over of keys from the root registry: `gatherClaims` and `hasPendingFragment` are deleted (the window gathers by the producer prefix and always engages). `adoptBoundary` captures the registry/gather pair it adopts under so a claim made long after — under the frame's hold, at a fragment's reveal — gathers against the root that holds the frame.
- `@solidjs/web`: `gatherHydratable`'s prefix-scoped gather selects its keys natively (`[_hk^="…"]`) instead of sweeping every `_hk` and filtering in JS — it now runs once per adopted occurrence, not only per late resume.
5 changes: 5 additions & 0 deletions .changeset/frames-plain-response-bound.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@solidjs/web": patch
---

frames: a plain (non-`live`) server component response ends at a streaming bound. A response whose content reads a standing source — a generator memo, a projection — used to stay open until the source settled, which for a source that never returns was never, with none of `live`'s reconnect semantics. The producer now ends it after `maxYields` emitting sweeps past the first flush (default 64) or `maxDurationMs` after the first flush (default 30 000 ms) — and when the request's `signal` aborts after the first flush — emitting `{ type: "complete", bound: "yields" | "time" }` before the body closes, and tears the render down quietly (sources returned, no abandonment finding). Both are new options on `FrameStreamOptions` (`renderServerComponent`, `renderToFrameStream`, `serverComponentResponse`); a `live` response is never bounded. The client stores `:bound` beside `:complete` and, in dev, warns once per cut-off naming `live()` as the declared way past the bound. `createFrameSink` gains an optional fourth `hooks` argument (`onYield`) and its `end(bound?)` takes the bound. Additive wire; RFC addendum in `frame-streams-rfc.md`.
Loading
Loading