Repository navigation
Conversation
Every slot fill of the Solid binding is one `insert(end.parentNode, value, end, [...existing])` under the fill's owner: a static value is placed once with no effect, a reactive one binds the range as before, an adopted fill claims through `insertExpression`'s claim pass, disposal is the owner's. The frame-side copies of that lifecycle go — `normalizeSlotContent`, `isReactiveContent`, the in-place `settle` test, the no-range snapshot fallback — and so does the runtime's own range writer: `#replaceRange` and the returned-nodes path through `#syncSlots` / `#invokeSlot` / `regions.bind(…, start)`. A `Slot` callback owns its range (places or binds before `ctx.range.end` over `ctx.existing`); its return value is no longer read. The runtime's never-used comment-marker range mode (`#start` / `#end`, `#parent`, `#firstContent`, `#clearContent`) goes: the frame element IS the range; `FrameImpl(element, options)`. The second claim window of a fill (the insert) gathers nothing — the first window's gather is in the registry, and gathering again put the keys the evaluation had claimed back as unclaimed. The binding's minted owner is transparent, so a fill mounting inside the hydrate pass consumes no id from the adopting component's counter. C1 (b) re-pinned to the core's rule: a fill answering a t=0 claim with fresh nodes is a hydration mismatch — the server node stays, nothing is duplicated, hydration reports it unclaimed (it asserted the frame's replacement before). The raw-frame pins place their output through `ctx.range` themselves. frames eager 35,250 / 11,654 → 34,272 / 11,367 (−978 min / −287 br); page base −979 / −217; page live −979 / −221; non-SC scenarios 0 / 0.
…/ live 39.92 KB); residue doc §7c landed table; plan §3 row R3; C1's contract text Caps lowered to measured + 10 B at the 0.01 KB step: frames eager 11.67 → 11.38 KB (34,272 min / 11,367 br), page base 36.50 → 36.29 (113,443 / 36,271), page live 40.14 → 39.92 (125,315 / 39,904); no cap raised. Residue doc: status line, §2 row 3 / §4 row 4 / §5 row 4 marked landed, §7c the measured → built table (ceiling −769 / −230; carrier −791 / −229, −600 / −160 with `#replaceRange` kept; the dead range mode −196 / −67; one copy −988 / −301; built −978 / −287), what `insert` owns, the two things the build found (no re-gather on the second claim window; the transparent binding owner), the C1 (b) re-pin, the `Slot` surface change. Plan §3 row R3. Consistency contract: C1's second arm is the core's mismatch rule; the mechanism and table rows name `insert`.
🦋 Changeset detectedLatest commit: 8a0b090 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 3 of the frames size pass (
documentation/plans/frames-residue-pass.md§2 row 3 / §5 row 4 — R.insert) onsize/frames-residue-2-pull-form(#3864) @f12708386. Draft; the base has not moved. Two commits: the item (source + tests + changeset) and the ratchet / docs. Measured on an edited copy of this head's dist through the size harness's own bundler before it was written (§0 method); the table below is measured vs built.Summary
insert. Each slot fill of the Solid binding is oneinsert(end.parentNode, value, end, [...ctx.existing])under the fill's owner: a static value is placed once with no effect created, a reactive one binds the range as before, an adopted fill claims throughinsertExpression's claim pass, disposal is the owner's. The frame-side copies of that lifecycle are gone —normalizeSlotContent,isReactiveContent, the in-placesettletest, the no-range snapshot fallback — and so is the frame runtime's own range writer:#replaceRangeand the returned-nodes path through#syncSlots/#invokeSlot/regions.bind(…, start).createFramemarker-less. The runtime's never-used comment-marker range mode (#start/#end— null on both constructors since the element-seams decision;#parent,#firstContent,#clearContent, theendbounds passed as null to every walker) is deleted: the frame element IS the range,FrameImpl(element, options). −196 min / −67 br alone; not in the residue doc's §2 — found while making the row's "the frame element is the range" literal.claimRender/slotsFor, ≈ +14 br over the edited copy): the fill's second claim window — the one around theinsert— must not re-gather (gathering the prefix again put every key the evaluation had just claimed back as unclaimed: 20 hydrate files red untilclaimRendertook aboundflag; the reactive path had the same latent re-gather, masked because its content claims inside that window); and the minted binding owner must be transparent (a non-transparentcreateOwner()inside the hydrate pass consumed a child id from the adopting component's counter, so a keyed sibling after the frame keyed by timing —container-trace-hold-id-determinism).c01-claim-once(b).Measured-before-written
Edited dist copies through
scripts/size's bundler (.wt-logs/res3-edit.mjs,res3-measure.mjs); base =f12708386(frames eager 35,250 / 11,654; page base 114,422 / 36,488; page live 126,294 / 40,125). min / br. The four non-SC scenarios 0 / 0 on every row.normalizeSlotContent,isReactiveContent,settle, the no-range fallback,#replaceRange+ both call sites)#replaceRangeKEPT (the rawSlot"return nodes" contract preserved;insert(end.parentNode, value, end, [...existing]); a range without an end marker left as rendered)#replaceRangegone (theSlotcallback owns its range)#replaceRange) + range mode, one copyboundflag and the transparent ownerCeiling −230 (the doc's −207); carrier as written −229 → with the range mode −301 measured, −287 built; the stop rule was net < −120.
vs
next@9d89df731(the pass's recorded measurement): frames eager −9,142 / −2,420; page base −32,314 / −8,611; page live −32,405 / −8,691; the four non-SC scenarios as the base (hydrating +110 / +142 / +52 br vsnextare the base's A0 Size-Exceptions — 0 vs base; CSR 0); server renderToString +4 / −9 (as the base).Public API changes
All
@experimental, on@solidjs/web/frames.Slot(FrameOptions.slotsofcreateFrame/createFrameElement). Before:(props, ctx) => Node | Node[] | undefined— returned nodes were placed by the frame between the range's markers (#replaceRange),undefinedclaimedctx.existingin place. After:(props, ctx) => void— the callback owns its range: it places or binds its output beforectx.range.endoverctx.existing(the Solid binding does this throughinsert); the return value is not read. The four raw-frame tests (lifecycle-matrix/call-driven-slots×2,server/frame-hn×2) place throughctx.range.createFrame(boundary: Element, options?)andcreateFrameElement(options)keep their signatures; the internal constructor isFrameImpl(element, options)(was(element, start, end, options)with the markers always null).SlotContext.rangeis documented as absent for a range whose end marker is missing (FRAME_MARKER_CORRUPTED, reported at discovery in dev); the Solid binding leaves such a range as the server rendered it. Before, it filled the range at the parent's end from a snapshot of the value (the "No range handle … degrade to the snapshot" path the residue doc named as the item's surface question).insertExpression); a fill's binding owner is transparent (no ambient id consumed at t=0 — the reactive path used to consume one).regions-tier.tsbind(frame, occurrence)loses itsstartre-scan parameter (the frame never reads a fill's output back).Pins
c01-claim-once(b) "a fill returning fresh nodes replaces its range; no server node of the range is left beside the clone" → "a fill returning fresh nodes at the claim is a hydration mismatch: the server node stays, nothing is duplicated, hydration reports it". The old arm pinnedsettle+#replaceRange's rule — a frame-side replacement during a claim pass — which is exactly what R.insert deletes; underinsert, a claim pass moves nothing (insertExpression's phantom rule), so the fresh render is dropped and the completion sweep namessc-<fid>-item#1-unclaimed. The new arm asserts that (the server node, no.fresh,textContent"onetwo", one "unclaimed" warning, no error).documentation/server-components/frames-consistency-contract.mdC1's second arm reads "left as the server rendered it and reported". If the frame-side replacement is wanted instead, R.insert's static path cannot beinsert(a claim pass cannot replace) — the item would keepnormalizeSlotContent+settle+#replaceRangefor the mismatch case, ≈ 70 br of the item.c01-claim-window-roots,adopted-swap-post-done,boundary-arrival,tier-bind-hold(the two replay arms), the lifecycle matrix (remount,call-driven-slots,document-adoption, …),frames-*mount / unmount / dispose specs, the hydrate suite.pnpm types+test-typesclean. Harness 500 cases × seeds 3289 / 91501: SC arm 0 findings; generic arm (CONSISTENCY_IGNORE=C1,C9,C19,E) 0 findings.welcome-status-streamed.jsonmoved on this machine as it does on the untouched base (the streamed render's chunk order); 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.67 → 11.38 KB (recorded minified 34,272); page base 36.50 → 36.29 (113,443); page live 40.14 → 39.92 (125,315). The three scenarios over their cap at the base (signals floor, isPending, CSR) are byte-identical to the base.Frames eager absolute: 11,367 br — 1,367 B above the ≤ 10 KB target.
Not done
Slotcallback that still returns nodes (its return is silently ignored now). Not added: a new diagnostic code is its own surface item; the type (=> void) and theSlotdoc carry the contract. Worth a"_SOLID_DEV_"-only warning if raw consumers exist outside the test suite..failsC10 parity pin incontainer-trace-hold-id-determinism(the server's root-id consumption for a boundary component) is untouched; the client now consumes no ambient id per fill (the reactive path consumed one before), which is the id-neutral side of that gap.Docs
frames-residue-pass.md: status line; §2 row 3, §4 row 4, §5 row 4 marked landed; §7c "Landed — residue step 3" with the measured → built table, whatinsertowns, the two build findings, the C1 (b) re-pin, the surface change, the running number.frames-savings-pass.md§3: row R3.frames-consistency-contract.md: C1's statement, mechanism, pin and table row.