Repository navigation
Conversation
… zombie heuristic, the default reveal seam, the brand) Five of the residue pass's seven D units (frames-residue-pass.md §1.4 / §2), measured on an edited dist before writing (frames eager, min / br, each alone against the C6 head 36,007 / 11,901; non-SC scenarios 0 / 0): - 2b `documentAddress` and its call: −95 / −44. An adopted mount's address comes with its binding (every serialized reference resolves to the call's binding; a `dynamic` mount is called with the live accessor); a mount with no binding — the per-function placeholder rendered directly — binds the function id. `adopted-claim-args-address.spec` mounts the binding (the production shape) and now asserts the store the frame bound. - 2c the second dispose map folded into `fillScopes`: −73 / −24. A live range binding's `insert` lives under the fill's own owner where there is one (stream-mounted), else under an owner registered the same way, so a re-call disposes whichever path the previous invocation took. - 2e the zombie heuristic and `#slotNodes` (its only reader): −186 / −68. The morph relocates ranges among siblings and recreates nothing (DR-5); "mounted" is `#mountedSlots`. Principles §9.2.3 / the bind notes amended. - 2f the imperative branch of `#revealSegment`: −34 / −19 as built (the ceiling −121 / −30 would make `FrameOptions.reveal` required; a default seam keeps it optional). A frame created without `reveal` reveals through `revealAtOnce` — `content()` inserted before the closing comment, the comment removed — so the content is applied as it is revealed on both paths. A placeholder missing its closing comment is not revealed (dev error; `#showFallback` already materialized nothing there — the boundary path threw on the null anchor before). - 2g `showing`'s brand on the bare per-function component: −95 / −20. The reference a reader holds at t=0 is the bootstrap's binding for the address, branded there. Not taken: 2d the capture arm (`contentHTML` + the last-unmount capture, −272 / −90) — `lifecycle-matrix/remount` › "away/back over a t=0 adopted boundary" pins it (the captured interior shows while the refetch is in flight); the residue doc called it unpinned. 2a the `_$SC` mirror needs the server's unconditional bootstrap — a later step. Together (edited dist): −721 / −210 on frames eager. Pins: web client, hydrate + consistency, server suites green. Co-authored-by: Cursor <cursoragent@cursor.com>
…export list Residue pass §2 row 5a, measured on an edited dist: −63 min / −25 br on frames eager (the scenario measures the whole entry with its export list; the pages tree-shake the two constants already — 0 / 0 there). Both stay exported from `@solidjs/web/frames/server`, where the header is read; the client sends the have-list itself (`resume`, through the handler). No consumer in the repo or in @solidjs/router's dist imports either name from the client entry (`frames-live-resume.spec` imports them from frame-transport). Public surface removal, `@experimental`. Co-authored-by: Cursor <cursoragent@cursor.com>
…ient, the RPC-seam re-ask deleted
Residue pass §3.3 (row 6b). A7's re-ask recorded the call per address and
re-invoked it by minting a reference through the RPC slot, copying the
declared metadata and honouring GET — 165 min of `reask` plus two
symbols, because `handle` saw `{ id, meta, args }` and no callable. The
server-function client has the call in hand at both places a frames
handler records one, so it hands the call over as a thunk:
- `dispatchServerFunction`: `ctx.retry = () => fetchServerFunction(base,
id, sent, args, meta, callArgs)` — the options as the caller sent them
(captured before this dispatch's controller is spliced in, so the
re-ask mints its own; a caller-supplied signal rides along, as it owns
the wire). A GET-declared read's `base` is its query url, so GET stays
GET by construction.
- the intercept sites (`createServerReference`'s `run`, `GET`'s `run`):
`info.retry` is the `send` the document's answer pre-empted. (`live`'s
intercepts carry none: the handler records no live call — the loop owns
its reconnects.)
The frames client's re-ask is `callFor(address).retry()`; the `reask`
installer in `installServerComponents`, its reads of the RPC slot and the
metadata brand, and `createServerReference` on the client half of the RPC
slot (`provideRPC`) go — the router reads `GET` / `decodeResponse` off the
slot, nothing read `createServerReference`.
Measured on an edited dist: frames eager −260 min / −99 br; page base
−230 / −30; page live −235 / −65 (the pages carry the sf client's +≈80
min thunks and still shrink). Non-SC 0 / 0. Pins: the nine arms of
`frames-errored-reset-refetch` (incl. (b) GET re-asks over GET, (c) a
wire failure errors the node and a further reset re-asks) and
`hydration/frames-adopted-error-outward` (the intercepted call re-asked
over the wire) green unchanged.
Public surface: `responseHandler.handle`'s ctx gains `retry()`;
`responseHandler.intercept` (an existing seam, now on the type) carries
`retry()` on its info; `callFor` (`@internal`) returns the call with its
`retry`; `getServerFunctionRPC()`'s client half loses
`createServerReference(id)` (`@internal`).
Co-authored-by: Cursor <cursoragent@cursor.com>
…27.9 K / R 2.4 K / F 7.9 K / D 1.8 K min; R+D 1,126 br measured), 24 candidate cuts measured on edited dist copies, the path from 11.84 KB (post-C6) to ≤ 10.0: the residue proper stalls at ≈ 10.4 with C2; crossing needs both C1 (holes) and the claims chunk → ≈ 9.67 KB with ≈ 330 B of margin (cherry picked from commit dae7d13)
…/ live 40.14 KB); residue doc §7 landed table; plan §3 row R1 Caps lowered to measured + 10 B at the 0.01 KB step for the three scenarios this step shrank — frames eager 11.92 -> 11.67 KB (35,250 min / 11,654 br), page base 36.66 -> 36.50 (114,422 / 36,488), page live 40.30 -> 40.14 (126,294 / 40,125); the two unrelated caps the ratchet would also lower are left alone; no cap raised (check-floor-caps HEAD clean). frames-residue-pass.md: status line + §7 — the measured -> built table for every item of the step, the two it left out and why (the capture arm is pinned by lifecycle-matrix/remount; readHydratedValue is module-private), the running number (11,654; 1,654 B above the target). frames-savings-pass.md §3: row R1. Co-authored-by: Cursor <cursoragent@cursor.com>
🦋 Changeset detectedLatest commit: fce81d2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 12 packages
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 |
|
Residue step 1 of the frames size pass (
documentation/plans/frames-residue-pass.md§5 rows 2 and 6, + 5a) onfeat/frames-bind-tier(#3862, C6) @e7d6e9e34. Draft; rebases cleanly (the base has not moved). Branch = base + the cherry-pick of the residue doc (dae7d1337→2a33c338d, since #3862 does not carry it) + three item commits + the ratchet / docs commit. Every item was measured on an edited copy of this head's dist through the size harness's own bundler before it was written (re-attribution §7 method); the table below is measured vs built.Summary
documentAddressand its call; the second dispose map folded intofillScopes; the zombie heuristic and the#slotNodesmap it read; the imperative branch of#revealSegmentreplaced by a default seam (revealAtOnce) so there is one reveal path andFrameOptions.revealstays optional;showing's brand on the bare per-function component.FRAME_HAVE_HEADER/FRAME_HAVE_BUDGEToff the client entry's export list. Both stay on@solidjs/web/frames/server, where the header is read.ctx.retryonhandle,info.retryonintercept— and the frames re-ask for an errored boundary'sresetiscallFor(address).retry(). The RPC-seam re-ask (reaskinstaller, the two symbol reads,createServerReferenceon the RPC slot) is gone. GET stays GET by construction: a GET-declared read's thunk is its own query-url dispatch._$SCmirror (server half).Measured-before-written
Edited dist copies through
scripts/size's bundler; base =e7d6e9e34(frames eager 36,007 / 11,901; page base 115,087 / 36,647; page live 126,964 / 40,286). min / br. Non-SC scenarios 0 / 0 on every row.documentAddress#slotNodesrevealrequiredshowing's brandFRAME_HAVE_*off the entryreask's function form)vs
next@9d89df731(the pass's recorded measurement, identical in the C3 and integration records; consistent with #3862's deltas): frames eager −8,164 / −2,133; page base −31,335 / −8,394; page live −31,426 / −8,470; the four non-SC scenarios as the base (the hydrating scenarios' +110 / +142 / +52 br vsnextare the base's A0 Size-Exceptions — 0 vs base); server renderToString +4 / −9 (as the base).Public API changes
FRAME_HAVE_HEADER,FRAME_HAVE_BUDGETfrom the@solidjs/web/framesclient entry (@experimental; both remain on@solidjs/web/frames/server). No consumer in the repo or in@solidjs/router's dist imported them from the client entry (frames-live-resume.specimports them fromframe-transport).createServerReference(id)from the client half of the server-function RPC slot (getServerFunctionRPC(),@internal; A7 had added it). The router readsGET/decodeResponseoff the slot; nothing readcreateServerReference.callFor(address)(@internal) returns{ id, meta, args, retry }—retry()makes the same call again.ServerFunctionsClientConfig.responseHandler.handle'sctxgainsretry(): Promise<unknown>; theresponseHandlertype now declares the existingintercept(info)seam, whoseinfocarriesretry()too.createServerComponentHandler's returnedhandle/interceptsignatures carryretry?().ServerComponentHandlerOptionsunchanged.FrameOptions.revealomitted → the default seam reveals the segment at once (content inserted before the closing comment, the comment removed), with the content applied as it is revealed exactly as on the boundary path. A placeholder whose closing comment is missing is not revealed (dev error) — before, the imperative path appended at the parent's end and the boundary path threw on the null anchor.@experimentalhandler):handler.showing(address, id)no longer brands the bare per-function component withCOMPONENT_BINDING; it only mints the address's binding. The reference a reader holds at t=0 is the bootstrap's binding for the address (branded there)._$SC.r(id)) binds the function id, not an_$SC.aaddress record. Every serialized reference resolves to the call's binding, and adynamicmount is called with the live accessor, so the production paths carry the address with the binding;adopted-claim-args-address.specnow mounts the binding (the production shape) and asserts the store the frame bound.signalstill owns the wire, as the sf client rules for every dispatch); A7's RPC-seam form carried none.Pins
frames-errored-reset-refetch.spec— (a) catch → reset → new request, (a′), (b) a GET-declared read re-asks over GET with the same args, (c) a re-ask failing on the wire errors the node and a further reset re-asks, (d), (e), (e′), (f), (g) — andhydration/frames-adopted-error-outward.spec(the intercepted call re-asked over the wire) green unchanged.hydration/adopted-claim-args-address.spec: mounts_$SC.r(FID, ADDRESS)(the binding) instead of the bare placeholder + a seeded_$SC.arecord; keeps its claim assertions and adds "the store the frame bound is the ADDRESS's, not the wire id's".lifecycle-matrix/remount› "away/back over a t=0 adopted boundary" went red under the capture-arm cut → the cut is not taken (below).c16-reference-identity,c17-gate-bound-address,c07-store-is-truth,tier-assets-ready(×7 frames withoutreveal),frames-assets-client,frames-hn-client,preload-links-frame-client, the lifecycle matrix — green.pnpm types+test-typesclean. Harness 500 cases × seeds 3289 / 91501: SC arm 0 findings; generic arm (CONSISTENCY_IGNORE=C1,C9,C19,E) 0 findings.__artifacts__/*.jsonon every run; on this machinewelcome-status-streamed.jsonrecords a different chunk order than frames: C6 — binding-slot tier; _hk on event-slot consumers closes the replay window #3862 committed andwrite-before-resume.jsonflips between two chunkings run-to-run, on the untouched base sources too — timing of the streamed render, not this branch; both reverted.)Size
scripts/sizeon this head: every frames / page scenario under its cap;check-floor-caps.mjs HEAD: no cap raised. Caps lowered (measured + 10 B at the 0.01 KB step): frames eager 11.92 → 11.67 KB (recorded minified 35,250); page base 36.66 → 36.50 (114,422); page live 40.30 → 40.14 (126,294). The two unrelated caps the ratchet would also lower are left alone. The three scenarios over their cap at the base (signals floor, isPending, CSR) are unchanged by this branch.Frames eager absolute: 11,654 br — 1,654 B above the ≤ 10 KB target.
Skipped
contentHTML+ the host's last-unmount capture; −272 / −90 alone). Pinned:lifecycle-matrix/remount› "away/back over a t=0 adopted boundary: the interior captured at unmount re-materializes instantly, and the refetch (now a real request) morphs it" — the residue doc called it unpinned. Without it, an away/back over a document-adopted (SSR'd) boundary shows the covering<Loading>'s fallback while the refetch is in flight instead of the interior it showed. That is a ruling on holds-latest across a remount of the document face, not a cut; left in.readHydratedValueis module-private insolid/src/client/hydration.ts((initP, refresh, options), with a loading-window arm), so taking it is a newsolid-js/internalexport, not a 0-B re-export of an existing one. Skipped per the brief. Note for the maintainer: the frames copy inslotArgsProxystill lacks 2.0.0-rc.0 | Error Boundary not showing when expected #2997's rejection-observe fors === 2(the export would fix that too)._$SCmirror (−234 / −80). Needs the server to emit the bootstrap unconditionally on SC pages (≈ +200 B of document output) — a server-side change for a later step (§3.7). WithdocumentAddressgone here, the later step is the mirror alone.FrameOptions.revealrequired: −30 vs the seam's −19). Kept optional; ~10 test files construct frames withoutreveal.signal: the thunk carries the caller's options whole. Strippingsignalcosts ~20 min on the sf client for an edge (a caller-aborted call's boundaryreset); the sf client's own rule — a caller-supplied signal owns the wire — was kept instead. Flagged in case the maintainer wants the re-ask on a fresh signal.Docs
frames-residue-pass.md(cherry-picked onto this branch): status line; §7 "Landed — residue step 1" with the measured → built table, the two items left out and why, the running number; §5 rows 2 and 6 marked.frames-savings-pass.md§3: row R1.server-components-principles.md: the three zombie-heuristic mentions amended (§9.2.3 / the bind notes / the attribute-slot row).