Skip to content

frames: A0 correctness pass — S-flush, C3 hold, C5 data scope, C12 report, rulings - #3837

Merged
ryansolid merged 20 commits into
nextfrom
wip/frames-pass-integration
Oct 6, 2026
Merged

ryansolid merged 20 commits into
nextfrom
wip/frames-pass-integration

Conversation

@ryansolid

@ryansolid ryansolid commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

The frames A0 correctness pass, landed as one PR per the maintainer ("merge as one given all the checks"). It fixes the frames/hydration consistency reds under the A0 principle (server components are rendered data; a frame is one async value outward) and the frames rulings — S-flush (the address is an async source; the store is one response's; the occurrence's name decides its class; a reveal is an apply), the C3 hold (hydration-done counts the frame's holds — ruling 3.1, ruled), C5 (a data chunk is under the store's version guard), C12 (c)'s client half (a rejected server fragment is reported in dev; the client invents no error state) — and carries the A0 documents with the code: the contract (documentation/server-components/frames-consistency-contract.md), the rulings (documentation/server-components/frames-rulings.md), the prior-art comparison, the A0 axiom in server-components-principles.md, and the two plans (documentation/plans/frames-a0-reattribution.md, frames-savings-pass.md). Consistency harness (CONSISTENCY_FUZZ=1, 500 cases, seeds 3289 and 91501): only C19 remains (C18 0, C3 0, C2 0 on both seeds). Supersedes the stacked drafts #3830 (S-flush), #3831 (C3), #3832 (C5), #3833 (C12 c), #3834 (docs), and the closed #3827 (C18 — unrepresentable under S-flush; see "Anything else" below). Off next @ 49a8dca84.

Ruled 2026-10-06 (docs commit 00dbc8663, no code): the maintainer ruled the remaining open points ("other than that lets do your recommendations") — in frames-rulings.md: the status line (1.3, 1.4 full, 1.6 (i), 2.3, 3.3 ruled as recommended), 3.5 closed (superseded by default #3; kept as the diagnosis record), 3.6 ruled (iii) — the consumer parks (C19 ×2 flip with the A2b port, fix/frames-a2b-park-and-window; C11 read as "outside a claim's park"; the contract's R10 misread S1 as evidence for (i)), the slot/html wire order ruled unspecified with the client's tolerance as the pin (1.4 and the wire list), and the two Phase A gate judgment calls accepted (C19 red until A2b; C13 (a, b) / C12 (c2) stand with drafts, server PRs to follow) under "What the rulings do NOT decide". In frames-savings-pass.md: §6 each decision gains its Ruled 2026-10-06: line (8.0 — holes eager, C1 skipped; assets tiered; the tier wire; complete.bound; S1 at C3; decision 6 closed by this PR's holdBoundary form with the hydrateWindow form attempted in A2b; preserveModules after the tiers; claims on the router's chunk), §4.1 Measured (the Phase D floor by measurement: B.3 −3,692 on L8, adapters 0, E.b+ −462; end state page base ≈ 27.0 / 27.5 KB br, live ≈ 30.7 / 31.3; the router +12,137 br — the 30 KB target is without it; under 30 KB yes, on B.3), and the one sentence after §3's cumulative gates.

Public API changes

All @experimental (the frames surface) or @internal; nothing wire.

  • New FrameHost.landing(id: string): Promise<void> | undefined (@experimental) — the address-source seam: a promise while the address's first response is in flight, undefined once the address has a landing to show (or nothing has begun). S-flush.
  • New FrameOptions.hold?(): () => void (@experimental, adopt path; wired by adoptBoundary) — called when a sync leaves an adopted occurrence waiting, returns the release. C3.
  • New sharedConfig.holdBoundary?(id: string): () => void (@internal, solid-js; assigned by enableHydration(), absent in CSR bundles) — initBoundaryResume's registration for a holder with nothing to resume. C3.
  • Behaviour, no signature change (S-flush): FrameOptions.recordsPending is the document face's re-drain/re-sync trigger ("may the document still deliver records?"), no longer a classifier — a called occurrence (prop#n) found recordless waits on every sync, document or stream face; createFrameHost.register no longer calls frame.rebase() after a seed (the method stays on Frame); the handler applies a synthetic start chunk at an unstaged response's header (begin), so the address reads "in flight" from the header to the landing; a version bump or rebind replaces the host and frame stores wholesale (root, segments, slot records, the error — a producer must re-send slot records, as the sink does); the argsEquivalent dedupe arm is removed from FrameImpl.apply (argsEquivalent and clearStreamRecords deleted; the mount's #slotArgs compare is what preserves occurrence state across versions); landing resolves on the root, the stream's error, or its complete.
  • Behaviour (C5): a data chunk whose version is below the store's is dropped at createFrameHost.apply (n < undefined is false, so a raw host consumer's unversioned data applies as before).
  • Dev-only (C12 c): console.error in claimRegionFragments when a server <Loading> fragment inside an adopted server component rejected on the server (_SOLID_DEV_; 0 B prod). No new diagnostic code.
  • Untouched (pending 1b): ServerComponentHandlerOptions.onStream, FrameHostOptions.resolve / FrameHost.resolve, FrameHost.preview / Frame.preview, STAGED_DATA, the wire format (FrameChunk, the record keys, the DOM markers, the hydration data keys, the _$SC bootstrap).

Size

Head as CI measured it (Size run 37488785237 on 665bda838; identical to the local measurement byte-for-byte — every "minified vs recorded" in the size report is 0 B), base = next @ 49a8dca84 as CI measured it in the same run. Every scenario not listed is 0 B; the three pre-existing over-cap-within-allowance warnings (signals floor, isPending/latest, CSR) are at +0 B minified and are not raised.

scenario next min / br head min / br Δ min / br cap recorded min
frames: eager client consumer 43,310 / 13,770 43,414 / 13,787 +104 / +17 13.78 → 13.79 KB 43,310 → 43,414
app: hydrating (no stores) — frozen floor 52,567 / 17,672 52,626 / 17,728 +59 / +56 17.71 → 17.73 KB 52,567 → 52,626
app: hydrating + every store primitive family 91,625 / 28,888 91,684 / 28,924 +59 / +36 28.87 → 28.93 KB 91,625 → 91,684
app: compiled hydrating 99,198 / 30,957 99,257 / 31,023 +59 / +66 30.93 → 31.03 KB 99,198 → 99,257
page: base server components — frozen floor 145,599 / 44,864 145,757 / 44,882 +158 / +18 44.84 → 44.89 KB 145,599 → 145,757
page: live server components — frozen floor 157,562 / 48,527 157,720 / 48,595 +158 / +68 48.51 → 48.60 KB 157,562 → 157,720

Caps are set at the 0.01 KB step at or below CI-measured + 10 B (not rounded up past +10), each with its recorded minified; the dated ledger line is above each cap in scenarios.js. Commit size: raise frames/hydration caps for C3 hold (maintainer Size-Exception).

Size-Exception: maintainer accepted the C3 hold (ruling 3.1) cost for correctness, 2026-10-06 — the hydrating floor, both page caps (floor-caps.json) and the frames-eager / hydrating + stores / compiled hydrating caps (scenarios.js) are raised to CI-measured + 10 B, with their recorded minified.

The growth is the C3 hold: sharedConfig.holdBoundary in solid-js (≈ +59 B min on every hydrating page — one sharedConfig assignment whose arrow wraps initBoundaryResume and checkHydrationComplete; the unmangleable property name and the two calls are most of it) and FrameOptions.hold + #syncSlots' waiting flag + adoptBoundary's wiring in the frames client (≈ +288 B min). S-flush itself is −187 B min / −128 B br on the frames client (the gate twin, the re-arm/waiter and the dedupe arm deleted); C5 is ≈ +70 B min; C12 (c) is 0 B prod. Expected to come back and more with 1b (preview / stage's client half, ≈ 1,300 B min) — the ratchet lowers the caps then.

Decided by default (accepted by maintainer 2026-10-06)

The overnight pass ran unattended under "make the conservative choice, write it down, move on"; the maintainer accepted the defaults as made ("I trust you, nothing super flagged"). Each is written with its alternative in frames-rulings.md ("What the rulings do NOT decide → Decided by default").

  1. The gate releases at the new address's first flush, not its start (1.5; C17 a re-pinned) — a start is the response announcing itself; revealing an empty <solid-frame> at it is the flash the gate exists to prevent.
  2. A warm switch-back shows the committed value; the flight is not surfaced as pending (1.6; C16 d) — landing(address) is undefined once the address has a landing to show.
  3. The occurrence's name decides its class on every sync (1.4's open item; C18 made unrepresentable) — a called occurrence (prop#n) found recordless waits; a bare prop is direct-insert by design.
  4. 2.3's interim form landed with S-flush, not as its own step — the # scoping removed an accidental poll that had masked R3; the reveal cascade now applies an empty write at the frame's version ("a reveal is an apply").
  5. 1.2 by the store's version guard, not per-response data cells (C5) — ≈ 30 B against the cell's ≈ 140 B; the cell is deferred to 1b. 1.3 is thereby not built: no path for the forbidden resolution remains.
  6. 3.2's registration is initBoundaryResume's, keyed sc:<fid>, taken only while isHydrationInProgress() (C3) — the fragment bookkeeping needs a key no fragment uses; a hold on a page that never hydrated is the frame's business. Cost ≈ +59 B min on hydrating pages — the accepted cost above.
  7. 3.3's client half is a dev console.error, not a diagnostic code (C12 c, re-pinned as c1 green / c2 red) — a structured code is new surface; the server half (the blank template) is drafted, not coded.
  8. S-adopted (claimRegionFragments → fr.adopt) documented, not built — ≈ +80 B in solid-js on every hydrating page, on top of 6.
  9. The harness's C3 law exempts a done that fired at or after the mount's disposal — an oracle correction, not a contract change; verified to hide nothing on next.
  10. landing resolves on complete too — a response that completed landed what it had, so a completed response without html never holds a gate forever.

Smaller readings recorded in the drafts' bodies, not restated in the doc: the hold is one per frame, not per occurrence (3.2's shape); a data chunk with no version (a raw host consumer) applies as before; the two plan documents were brought as one squashed commit.

Not in this PR

  • 1b — FrameImpl#preview / stage's client half / #refArgsUnchanged (≈ 1,300 B min): the pull form (the fill's props memo reads the token and derives from the staged record) is written up in frames-rulings.md's as-landed table and fix(web/frames): the address is an async source — one landing per bound address, one response per store (S-flush) #3830's body; it touches the regions and binding-slot paths and needs its own gate run.
  • DR-4 structural (one reveal engine, 2c) and R.reveal's readiness/retry deletion — 2.3 landed in its interim form only.
  • 1.3's per-response cell (records carry their resolver), S-ref, S-record (C2 a2 stays red: a plain write into _$HY.r observed by nothing).
  • S-adopted (claimRegionFragments → fr.adopt; ≈ +80 B solid).
  • hydrateWindow / R.claim's deletion and the 3e port (S1's park; C19 ×2 stay red).
  • Wire drafts (frames-rulings.md, "The server half — drafts"): C13's sweep delimiter, complete.bound (the plain-response streaming bound), C12 (c)'s server template (render the nearest server <Errored>'s fallback into the <Loading>'s position). C13 (a, b) and C12 (c2) stay red until the server half.

Gate

  • packages/web: client 124 files / 1142 passed / 1 expected fail; server 154 / 1474 / 3 expected fail / 2 skipped; hydrate 68 (+1 skipped) / 358 passed / 6 expected fail (was 22 on next: C2 a2, C12 c2, C13 a, C13 b, harness C19 ×2 remain); test-types clean.
  • packages/solid: 41 files / 821 passed; test-types clean.
  • Harness, 500 cases: seed 3289 C3 280 → 0, C18 49 → 0, C2 27 → 0, C19 71 → 83; seed 91501 C3 268 → 0, C18 55 → 0, C2 51 → 0, C19 68 → 79. C19 rises by the cases that previously ended in C18/C2 — those occurrences now mount and expose the known R10 shape (3e's).
  • Changesets: frames-address-source (@solidjs/web), frames-hold-is-pending-boundary (solid-js, @solidjs/web), frames-data-response-scoped (@solidjs/web), frames-fragment-rejection-report (@solidjs/web). The docs and the cap change need none.

Anything else

ryansolid and others added 17 commits October 6, 2026 03:57
…nd address, one response per store (S-flush)

A0 (SCs are rendered data): a frame is one async value outward. The mount's
covering <Loading> now pends on the bound address's FIRST FLUSH — content or
error — through `FrameHost.landing(address)`, read per bound address through a
fresh node (frames-rulings 1.5, 1.6 (i)): a switch is a new question on the
source, the superseded address's late writes release nothing, an unrevealed
boundary stays on its fallback and a revealed one holds. The two hand-rolled
shell gates (`boundaryComponent`'s arm/release/settle/setGate and
`adoptBoundary`'s twin), `followAddress`'s re-arm and frameless waiter, and
`onApply`-as-release go. An unstaged response announces itself to the host at
its header (`start`), so the address reads "in flight" from the header to the
landing.

The store is one response's (1.4 full; 2.1/2.2): a version bump or rebind
replaces the store wholesale — root, segments, slot records, the error — so a
byte-identical root under a new version still applies as the new version's
(C7 c), a held record leaves with the response that carried it (C6 a1, b2),
and `argsEquivalent`/`clearStreamRecords` delete; the mount's `#slotArgs`
value compare is what preserves occurrence state. The host keeps the latest
landed version as `shown` so a mount opened mid-flight seeds the committed
value (holds-latest) and the landing fans out as the version's whole set.

The occurrence's name decides its class: a called occurrence (`prop#n`) found
without its record waits for it — never evaluated argless (C18 ×3 flip; the
#2968 poll stays as the document face's re-sync trigger, scoped to called
occurrences) — and a bare occurrence is direct-insert. A reveal is an apply
(2.3, interim): the document face's reveal cascade syncs the adopting frame,
so a direct-insert range the fragment carried mounts (C2 b) and a record
drained before its range was shown takes effect at the reveal (C4 d).

Pins flipped to `test`: C2 (b), C4 (d), C6 (a1, b2), C7 (c), C17 (a — re-pinned:
B's first flush, not its `start`, releases), C17 (c), harness C2 ×1, C18 ×3.
Re-pinned: frames-binding-slots "orphan record … waits" (was "still mounts"),
frames-hn-client zero-data occurrence is the bare prop.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…adopted occurrence is a pending boundary (C3)

Frames-rulings 3.1 (ruled): hydration-done follows non-SC Solid 2 — done is
what `checkHydrationComplete` says (the root pass over, `_pendingBoundaries`
zero), and the frames client participates through that mechanism, with no
accounting of its own. 3.2, the carrier: ONE registration per frame while a
sync leaves an adopted occurrence waiting to mount (for its record, for a
`{$ref}`'s data), released by the first sync that leaves none or by disposal.

solid-js: `sharedConfig.holdBoundary(id)` (internal) — `initBoundaryResume`'s
registration for a holder with nothing to resume: the count, the owner's `_hp`
mark, the disposal release; returns the release, which checks completion.
One assignment in `enableHydration`.

web/frames: `FrameOptions.hold()` (adopt path; wired by `adoptBoundary` under
the component's owner, only while `isHydrationInProgress()`, keyed `sc:<fid>`
so no fragment's bookkeeping is touched); `#syncSlots` tracks whether a full
sync left an unmounted occurrence waiting and registers/releases at its end;
`dispose` releases.

Harness: the C3 law exempts a done that fired at or after the mount's
disposal — a disposed holder owes no claim (its release is what lets done
fire, as a disposed <Loading>'s is). Verified to hide nothing on `next`
(C3 stays 280/500 there).

Pins flipped to `test`: C3 (a), harness C3 ×1. Campaign (500 cases): C3
280 → 0 (seed 3289), 268 → 0 (seed 91501); only C19 remains.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…(C5)

Frames-rulings 1.2: a `data` chunk lands in its own response's table or
nowhere. The integration rotates the address's table at the header and
creates it at first use; the transport restamps every chunk with its
response's version; but `createFrameHost.apply` routed `data` straight to
the data hook with no version read — so a superseded response's late chunk
was the first use and filled the table that was now the current response's
(R4). The data path is now under the store's version guard like every other
chunk: with the response announced to the store at its header (S-flush), a
`data` chunk whose version is below the store's is dropped.

Pins flipped to `test`: C5 (a), (b), (e).

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…n adopted frame in dev; the client shows the server's outcome (C12 c, client half)

Frames-rulings 3.3 under A0's corollary 4 (inward): a server `<Loading>`
inside a server component is the SERVER's boundary; its outcome arrives as
markup and the client shows whatever the server rendered for it — never a
blank it invents, never a client error fallback for a server state. A
rejected one has no client twin to surface its `<key>_fr` rejection
(`hydratedCreateLoadingBoundary`'s `s === 2` arm runs only for a boundary
registered against it), so the adoption that claims its placeholder
observes the rejection and names it in dev (0 B prod).

The blank the position shows today is the server half's gap: `server.ts`'s
error path hands `sink.fragment` a `" "` template (the client twin, when
there is one, renders over it; a server component's boundary has none).

Pins: C12 (c) re-pinned per 3.3 — (c1) the rejection is reported in dev,
the client invents no error state (test); (c2) the position shows the
server's rendered outcome, never a blank (test.fails, the server half).

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…n #syncSlots, the guard reads isHydrationInProgress alone

−48 B min on the frames client (43,411 → 43,363); the zombie check now
precedes the {$ref} wait, so a zombie held on a ref is unmounted at once
rather than when the ref resolves.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… false)

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ency reds and the size audit's duplicates share (proposed)

Draft, marked "proposed — maintainer ruling pending"; no engine changes.

The frames/hydration consistency contract (spec/frames-consistency-contract)
found thirteen reds across C2, C3, C4, C5, C6, C7, C12 and C17; the SC size
audit (size/sc-audit §4) listed the layer's duplicated seams. This document
tests the hypothesis that they are the same seams seen from two sides, and
drafts the rulings — numbered one-sentence statements in the L2 section's
voice, each with the mechanism that carries it today, the state it lives in
twice, and the reds it decides — grouped by the three questions the reds
cluster on:

- Response identity (C5, C6, C17): a response owns what it delivered; a
  `data` chunk lands in its own response's table or nowhere; a record
  resolves its refs through its own response's table wherever the frame is
  bound; a bump drops what the previous version never applied; the shell
  gate is the bound address's; a switch keeps on screen what was on screen.
- Applied state per version (C7, C2, C4): the store is the truth and the
  applied state is a cache of it keyed by version; a bump re-applies a
  byte-identical root; a reveal is an apply; applied means shown.
- Hydration-done accounting (C3, C12, S1's C3b and `.fails`): done counts
  every occurrence the document delivered; every frames hold is counted once
  per frame; a claim owns the fragment's outcome; the client consumes the
  ids the server consumed.

For each: the fix shape as one collapsed carrier (response-owned data
cells, records carrying their resolver, one shell gate, one applied record,
one hold counter), a byte estimate (− collapse / + carrier) read off the
audit's function table, the pins that flip, and what touches public
surface or the server half. Two-readings items for the maintainer: 1.4
(narrow/full), 1.6 (per-address gate value vs holds-latest), 3.1 (done
counts the page vs the root pass — S1's pin and the contract's contradict).
What the rulings do not decide (plain bugs, product questions, the wire)
and an order of work gated by the contract's pins and scripts/size.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
…19 under seam 3; gate is #3813

Co-authored-by: Cursor <cursoragent@cursor.com>
… data; a frame is one async value outward, its inner boundaries are the server's; 3.1 ruled

Co-authored-by: Cursor <cursoragent@cursor.com>
… hold model governs; axioms annotated with the Solid 2 rules they restate

Co-authored-by: Cursor <cursoragent@cursor.com>
Per-reading comparison (1.3, 1.4, 1.6, 2.3, 3.1, 3.3, 3.5, 3.6) and per-
product-question comparison (C12 (c), settles-once projections, live
containers, slot-trails-html) against RSC/Flight+Fizz, Next.js, React
Router/Remix, Turbo/htmx, Phoenix LiveView, Qwik, Astro server islands,
Marko, Vue and Solid Router. Adds an addressing section (content-keyed vs
tree-shaped vs DOM-addressed vs connection-tree) for the maintainer's A3/A4
model, a summary table, and a list of mechanisms the references have that
we don't. Primary-source citations; verified vs inferred marked.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…plan onto the rulings branch (from size/frames-a0-reattribution @ 1e0be39)

The plans tonight's correctness pass implements (frames-savings-pass.md
Phase A: A0–A6), carried with the code per the maintainer's preference.
Squashed from the branch's nine commits; content unchanged.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ts, the server-half drafts, the as-landed table

What the rulings do NOT decide: the nine readings the 2026-10-06 pass took
by default (first flush not start; warm switch-back shows the committed
value; the name decides the class on every sync; 2.3's interim with
S-flush; 1.2 by the version guard; 3.2 via initBoundaryResume keyed
sc:<fid> while in progress; 3.3's dev report; S-adopted documented; the
harness's C3 dispose exemption), each with its alternative. The server
half: C13's delimiter with the client's one-write status, the
plain-response streaming bound (complete.bound), C12 (c)'s error template
located in finalizeError/the done closure with the two decisions the
server PR must make. Order of work: the as-landed table (#3830–#3833),
what each step left undone. Public surface: landing, hold, holdBoundary,
the behaviour notes.

Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… decisions: the defaults accepted, the C3 hold cost accepted (caps raised), #3827 closed as superseded by S-flush

Co-authored-by: Cursor <cursoragent@cursor.com>
…ion)

The C3 hold (frames-rulings 3.1, ruled) costs +59 B min on every hydrating page (sharedConfig.holdBoundary in solid-js) and the pass nets +104 B min on the frames client (S-flush −187, the hold and C5's guard +291). Six scenarios are over their cap past the 20 B minified allowance; the maintainer accepted the cost 2026-10-06 ("pay the cost for correctness"). Each cap is set at the 0.01 KB step at or below measured + 10 B, with its recorded minified, from a local measurement that matches CI on this machine: hydrating (no stores) 17.71 -> 17.73 KB, page base 44.84 -> 44.89 KB, page live 48.51 -> 48.60 KB (floor-caps.json, under the PR's Size-Exception:); hydrating + stores 28.87 -> 28.93 KB, compiled hydrating 30.93 -> 31.03 KB, frames eager 13.78 -> 13.79 KB (scenarios.js). The three pre-existing over-cap-within-allowance scenarios (signals floor, isPending, CSR) are at +0 B minified and are not raised.

Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot

changeset-bot Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e968866

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@solidjs/web Patch
solid-js Patch
@solidjs/babel-plugin Patch
@solidjs/diagnostics Patch
@solidjs/element Patch
@solidjs/h Patch
@solidjs/html Patch
test-integration Patch
todos-server-example Patch
@solidjs/universal Patch
@solidjs/compiler Patch
@solidjs/signals Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

Size (brotli, eager entry chunk)

scenario head vs base minified vs base minified vs recorded cap lazy chunks (not counted)
signals: core floor (createSignal/Memo/Effect/Root/flush) 7.36 KB 0 B 0 B 0 B 7.35 KB ⚠️ over by 11 B, 20 B minified headroom
signals: + createStore 14.54 KB 0 B 0 B 0 B 14.56 KB ✅
signals: + isPending/latest 9.51 KB 0 B 0 B 0 B 9.49 KB ⚠️ over by 23 B, 20 B minified headroom
app: render + one signal (the simple-app floor) 9.86 KB 0 B 0 B 0 B 9.86 KB ✅
app: hydrating (no stores) with Show/For/Loading/Errored/lazy 17.73 KB +56 B (+0.3%) +59 B 0 B 17.73 KB ✅ lazy-page.js 0.04 KB
app: hydrating + every store primitive family 28.92 KB +36 B (+0.1%) +59 B 0 B 28.93 KB ✅ lazy-page.js 0.04 KB
app: CSR with Show/For/Loading/Errored/lazy 12.90 KB 0 B 0 B 0 B 12.86 KB ⚠️ over by 45 B, 20 B minified headroom lazy-page.js 0.04 KB
app: CSR, observe tier (same app on the observe artifacts) 14.45 KB 0 B 0 B 0 B 14.46 KB ✅ lazy-page.js 0.04 KB
app: CSR, observe tier + attribution engine enabled 28.64 KB 0 B 0 B 0 B 28.66 KB ✅ lazy-page.js 0.04 KB
app: compiled floor (one template, one text hole, one delegated click) 10.03 KB 0 B 0 B 0 B 10.05 KB ✅
app: compiled CSR (JSX todo app: spread/merge/omit, events, class/style, keyed For, Show, Loading + lazy, store) 25.13 KB 0 B 0 B 0 B 25.13 KB ✅ stats.js 0.18 KB
app: compiled hydrating (the same JSX todo app through hydrate(), compiled hydratable) 31.02 KB +66 B (+0.2%) +59 B 0 B 31.03 KB ✅ stats.js 0.20 KB
frames: eager client consumer (frames client + transport, lazy codec) 13.79 KB +17 B (+0.1%) +104 B 0 B 13.79 KB ✅
page: base server components (hydrating + dynamic + frames + sf reference) 44.88 KB +18 B (+0.0%) +158 B 0 B 44.89 KB ✅ decode.js 6.07 KB, lazy-page.js 0.04 KB
page: live server components (base + live/GET + action + isPending/latest) 48.59 KB +68 B (+0.1%) +158 B 0 B 48.60 KB ✅ decode.js 6.07 KB, lazy-page.js 0.04 KB
server: floor (getRequestEvent + isServer) 1.33 KB 0 B 0 B 0 B 1.34 KB ✅
server: renderToString (the server-render floor) 20.41 KB 0 B 0 B 0 B 20.42 KB ✅

⚠️ Over the brotli cap within the minified allowance (passes)

  • signals: core floor (createSignal/Memo/Effect/Root/flush): over brotli cap by 11 B; minified 20,133 B vs 20,133 B recorded with the cap (+0 B) — 20 B of the 20 B minified allowance left; +0 B minified over this PR's base
  • signals: + isPending/latest: over brotli cap by 23 B; minified 26,828 B vs 26,828 B recorded with the cap (+0 B) — 20 B of the 20 B minified allowance left; +0 B minified over this PR's base
  • app: CSR with Show/For/Loading/Errored/lazy: over brotli cap by 45 B; minified 36,568 B vs 36,568 B recorded with the cap (+0 B) — 20 B of the 20 B minified allowance left; +0 B minified over this PR's base

Bundled with Rolldown (what Vite ships), brotli q11, decimal KB. A scenario fails only when it is over its brotli cap and its minified size is more than 20 B over the minified recorded with the cap; over the cap within that allowance is brotli layout noise and passes with a warning. Caps and their recorded minified in scripts/size/scenarios.js; the floor and page caps in floor-caps.json are frozen (lower only, or Size-Exception: in the PR body). npm run ratchet lowers caps per RC; it never raises one (scripts/size/README.md).

@coveralls

coveralls commented Oct 6, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 37514156882

Coverage decreased (-0.1%) to 75.927%

Details

  • Coverage decreased (-0.1%) from the base build.
  • Patch coverage: 2 uncovered changes across 1 file (1 of 3 lines covered, 33.33%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
packages/solid/src/client/hydration.ts 3 1 33.33%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1199
Covered Lines: 964
Line Coverage: 80.4%
Relevant Branches: 932
Covered Branches: 654
Branch Coverage: 70.17%
Branches in Coverage %: Yes
Coverage Strength: 28.16 hits per line

💛 - Coveralls

@codspeed

codspeed Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 188 untouched benchmarks


Comparing wip/frames-pass-integration (e968866) with next (59fb244)

Open in CodSpeed

… holes eager) and the measured Phase D floor

Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid added a commit that referenced this pull request Oct 6, 2026
…ark is unconditional; hydrateWindow's hydrating cost accepted

- frames-rulings 3.6: "Landed" — the park is unconditional (post-done claims under corollary 4 have no hydration state that says "claim"); S1's `claiming` hint at plan step C3 keys it on the claim again.
- frames-rulings 3.2: cost as landed — #3837 + #3840, frames −109 br / hydrating +105 br; the hydrating cost accepted, caps raised under a Size-Exception at the next integration PR.
- consistency contract R10 / C19: the park's key described as it landed.
- savings-pass plan §3 row A2: landed in two parts, measured vs estimate, further solid-side seams measured on an edited dist copy before they are written.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants