From 9cb8f7e1d1d4cb6a9625de8c6fa04af9cf27303b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 13:41:27 +0000 Subject: [PATCH 1/4] fix(signals): a held frame's leaf is the hold's own work, not its verdict reader (E2) A render effect in a frame a held pass built (CONFIG_HELD_FRAME, e.g. the branch ` 0}>` opens under an action holding `y`) re-run by the hold's next step showed two ways depending on memo wrapping: - inline `latest(y)`: `route` seated it as the hold's verdict reader, so its run went out at the verdict lane's reveal, ahead of its frame; - `createMemo(() => latest(y))` read plainly: `laneRead`'s L7' arm served the memo's staging as the hold's own value and the run waited for the landing (and a later run, with nothing staged, entered the verdict lane through `enterLane`). `[10, 20]` beside `[10]` for one hold; with #4455, the two-hold review shape (`[latest(y), m()]` inline vs a memo of it, or split leaves) the same. A member of the hold's held frame is born in its world: it reads plainly and a probe does not rescue it (D-25, as #4426/#4454 for its reads), and its runs are the frame's, which commits with the hold (D-27's joined pass, A29 ruling A). `route` and `enterLane`'s verdict arm now leave it the frame's when the lane's hold is the one it was born into; every form waits for the landing (the branch is not on screen before it). The reader-seat table carries the same clause (test-only). #4455's pin (`verdict-seat-merged-lane-4427`) asserted the inline leaf running ahead of its held frame (`1/20` at A's step); it now expects the frame's `1/10` until B's landing, and gains the mainline-mount contrast (` 0}>`), which still shows `1/20`. Lives in verdict.ts / lanes.ts only: 0 B on every floor. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2 --- .changeset/held-frame-verdict-parity.md | 5 + packages/signals/docs/RULES-INDEX.md | 2 +- packages/signals/src/core/lanes.ts | 12 +- packages/signals/src/core/seat.ts | 23 ++- packages/signals/src/core/verdict.ts | 14 +- .../tests/held-frame-verdict-parity.test.ts | 181 ++++++++++++++++++ .../verdict-seat-merged-lane-4427.test.ts | 134 +++++++------ 7 files changed, 301 insertions(+), 70 deletions(-) create mode 100644 .changeset/held-frame-verdict-parity.md create mode 100644 packages/signals/tests/held-frame-verdict-parity.test.ts diff --git a/.changeset/held-frame-verdict-parity.md b/.changeset/held-frame-verdict-parity.md new file mode 100644 index 0000000000..b8760437bd --- /dev/null +++ b/.changeset/held-frame-verdict-parity.md @@ -0,0 +1,5 @@ +--- +"@solidjs/signals": patch +--- + +A render effect in a branch an action holds (` 0}>` opened by the action's write) no longer runs ahead of that branch's landing when it reads `latest(y)` inline, while the same read through a memo waited: a member of the frame a held pass built is the hold's own work, so neither form seats it as the hold's verdict reader, and memo wrapping no longer changes what it shows. diff --git a/packages/signals/docs/RULES-INDEX.md b/packages/signals/docs/RULES-INDEX.md index 60cb02877c..769d779782 100644 --- a/packages/signals/docs/RULES-INDEX.md +++ b/packages/signals/docs/RULES-INDEX.md @@ -73,7 +73,7 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul | A26 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:111` | — | action-await-contract.test.ts×2 fuzz-findings-l2.test.ts×1 posture-store-parity.test.ts×2 visibility-oracle-store.states.ts×2 visibility-oracle.states.ts×1 visibility-oracle.test.ts×1 | [ruled 2026-07-17] An ambient transaction window is one flush; parking is flush-driven — (**ruled 2026-07-17**, #2913; **enforcement hardened 2026-08-31**, #3141 — parking is flush-driven, and a trans… | | A27 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:303` | — | loading-value.test.ts×2 visibility-oracle.states.ts×18 visibility-oracle.test.ts×1 | [ruled 2026-08-10] The commit-#0 loading window is loading-class and verdict-quiet — (**ruled 2026-08-10**) **The commit-#0 loading window is loading-class and verdict-quiet.** A node born committed v… | | A28 | ruled, mechanism landed | `docs/SPEC-ASYNC-SEMANTICS.md:95` | constants.ts×1 core.ts×12 lanes.ts×2 scheduler.ts×3 seat.ts×3 types.ts×1 verdict.ts×2 store.ts×5 | continuation-sibling-reader-4146.test.ts×1 createOptimistic.test.ts×5 fuzz-findings-l2.test.ts×6 held-derivation-not-a-proposal-3612.test.ts×1 issue-3800-repro.test.ts×1 latest-held-till-flush.test.ts×1 latest-memo-inline-parity.test.ts×1 posture-store-parity.test.ts×5 question-scoped-pending.test.ts×3 snapshot-derived-store-rows.test.ts×1 createOptimisticStore.test.ts×10 optimistic-draft-visibility-3665.test.ts×5 optimistic-list-mutation-matrix.harness.ts×1 optimistic-list-mutation-matrix.test.ts×2 shallow.test.ts×1 woken-transaction-adopts-staged-bump.test.ts×1 treeshake.test.ts×2 verdict-contract.test.ts×1 visibility-oracle-store.states.ts×8 visibility-oracle.states.ts×8 | [ruled, mechanism landed 2026-09-15] A write becomes visible at flush — to every channel — (**ruled 2026-09-08**; supersedes the #2922 mid-tick pull) **A write becomes visible at flush — to every chan… | -| A29 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:119` | boundaries.ts×1 action.ts×1 constants.ts×1 core.ts×14 effect.ts×1 lanes.ts×1 scheduler.ts×4 seat.ts×1 signals.ts×1 store.ts×1 | adoption-unchanged-key-read-3706.test.ts×9 body-end-supersession-visibility.test.ts×1 born-held.test.ts×3 boundary-not-born-held-3540.test.ts×4 createProjection.draft-lifetime-3585.test.ts×1 direct-commit-readers-posture.test.ts×1 fuzz-findings-l2.test.ts×6 held-branch-verdict-reader-4010.test.ts×1 held-conditional-memo.test.ts×1 held-frame-dependencies.test.ts×2 held-truth-lane-only.test.ts×3 l2-contract.test.ts×1 latest-held-till-flush.test.ts×2 loading-fallback-in-flush-3540.test.ts×6 loading-on-frame-following-3540.test.ts×1 mount-over-foreign-hold-3761.test.ts×1 optimistic-mount-nested-memo-3835.test.ts×1 optimistic-read-lane-not-transaction-3698.test.ts×3 posture-born-held-and-observation.test.ts×1 posture-store-parity.test.ts×6 derived-presence-async-3726.test.ts×3 optimistic-untracked-reads-f3-f5.test.ts×1 store-unchanged-read-independent-write-3688.test.ts×1 tick-scoped-pass-transaction.test.ts×2 treeshake.test.ts×3 verdict-born-into-other-flush-4426.test.ts×1 verdict-mount-first-pass-3851.test.ts×2 verdict-mount-loading-flush-loop.test.ts×2 visibility-oracle-store.states.ts×5 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×9 visibility-oracle.test.ts×1 write-proposals-3494.test.ts×1 | [ruled, amended in place 2026-09-13 (#3408)] A tracked read served a live transaction's staged value enters that transaction — A tracked computation served a node's staged `_pendingValue` — a value a … | +| A29 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:119` | boundaries.ts×1 action.ts×1 constants.ts×1 core.ts×14 effect.ts×1 lanes.ts×1 scheduler.ts×4 seat.ts×1 signals.ts×1 store.ts×1 | adoption-unchanged-key-read-3706.test.ts×9 body-end-supersession-visibility.test.ts×1 born-held.test.ts×3 boundary-not-born-held-3540.test.ts×4 createProjection.draft-lifetime-3585.test.ts×1 direct-commit-readers-posture.test.ts×1 fuzz-findings-l2.test.ts×6 held-branch-verdict-reader-4010.test.ts×1 held-conditional-memo.test.ts×1 held-frame-dependencies.test.ts×2 held-frame-verdict-parity.test.ts×1 held-truth-lane-only.test.ts×3 l2-contract.test.ts×1 latest-held-till-flush.test.ts×2 loading-fallback-in-flush-3540.test.ts×6 loading-on-frame-following-3540.test.ts×1 mount-over-foreign-hold-3761.test.ts×1 optimistic-mount-nested-memo-3835.test.ts×1 optimistic-read-lane-not-transaction-3698.test.ts×3 posture-born-held-and-observation.test.ts×1 posture-store-parity.test.ts×6 derived-presence-async-3726.test.ts×3 optimistic-untracked-reads-f3-f5.test.ts×1 store-unchanged-read-independent-write-3688.test.ts×1 tick-scoped-pass-transaction.test.ts×2 treeshake.test.ts×3 verdict-born-into-other-flush-4426.test.ts×1 verdict-mount-first-pass-3851.test.ts×2 verdict-mount-loading-flush-loop.test.ts×2 visibility-oracle-store.states.ts×5 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×9 visibility-oracle.test.ts×1 write-proposals-3494.test.ts×1 | [ruled, amended in place 2026-09-13 (#3408)] A tracked read served a live transaction's staged value enters that transaction — A tracked computation served a node's staged `_pendingValue` — a value a … | | A30 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:259` | async.ts×3 attribution.ts×1 constants.ts×1 core.ts×1 effect.ts×1 lanes.ts×1 scheduler.ts×5 projection.ts×1 | async-landing-deps-3461.test.ts×3 fuzz-findings-l2.test.ts×3 held-conditional-effect.test.ts×1 held-conditional-memo.test.ts×1 held-frame-dependencies.test.ts×2 ispending-in-boundary-on-3528.test.ts×1 lane-frame-deferred-run-3662.test.ts×1 lane-frame-held-lane-3662.test.ts×1 posture-born-held-and-observation.test.ts×1 projection-peek-loop-4342.test.ts×1 treeshake.test.ts×2 write-proposals-3494.test.ts×2 zombie-rerun-after-commit-3546.test.ts×2 | [ruled 2026-09-13 (#3410)] A memo's dependencies are the committed frame's until the frame is replaced — A pass that _staged_ its value has not replaced the committed frame, so the committed value sti… | | A31 | live | `docs/SPEC-ASYNC-SEMANTICS.md:133` | boundaries.ts×1 core.ts×1 lanes.ts×1 seat.ts×1 verdict.ts×2 | fuzz-findings-l2.test.ts×6 ispending-combined-atomic-3442.test.ts×1 unowned-memo-ispending-reader-4366.test.ts×1 | [live 2026-09-14 (#3442)] A memo computes under its own lane posture, never its puller's — A memo's value is one shared slot every reader sees, so its pass runs under the lane posture the memo itself … | | A32 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:141` | core.ts×4 lanes.ts×1 seat.ts×1 store.ts×1 | visibility-oracle-store.states.ts×8 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×9 visibility-oracle.test.ts×1 | [ruled 2026-09-14] Children-forbidden readers see the frame, not the graph — `createTrackedEffect` and `onSettled` callbacks are effect-phase code that runs after the frame is decided. They read the f… | diff --git a/packages/signals/src/core/lanes.ts b/packages/signals/src/core/lanes.ts index 515d3580ce..0ba115d99d 100644 --- a/packages/signals/src/core/lanes.ts +++ b/packages/signals/src/core/lanes.ts @@ -286,7 +286,17 @@ export function enterLane(l: Transaction, c: Computed): void { // does not break it out — it stays the frame's, as the same read inline // does (verdict.ts `markVerdictReader`, `route`; D-25, D-26). An // effect's own reads do not count (its `_type`, 1–3, carries neither bit). - if (!(verdict && creatorReads(c, (c as any)._type || f))) { + // Nor by a member of the frame a held pass of that lane's hold built, + // on any later run (CONFIG_HELD_FRAME, `bornInto`): born in the hold's + // world, it is the hold's own work and its run is the frame's, at the + // landing (D-25, D-27) — as `route` keeps it for the inline `latest()`. + if ( + !( + verdict && + (creatorReads(c, (c as any)._type || f) || + (c._config & CONFIG_HELD_FRAME && bornInto(c, resolveTx(l._parent!)))) + ) + ) { setPassLane(l); // The pass read a held write before its first lane read (it joined the // frame's future as mainline would): lane work sees the screen — the diff --git a/packages/signals/src/core/seat.ts b/packages/signals/src/core/seat.ts index 8b0100f45e..f6ef6fdecd 100644 --- a/packages/signals/src/core/seat.ts +++ b/packages/signals/src/core/seat.ts @@ -395,8 +395,17 @@ function applyRaise(seat: Seat, p: Prediction): void { if (seat.ownWorld > seat.world) seat.world = seat.ownWorld; // Display-ahead (today `route`): the pass is the hold's verdict reader // unless already seated, or already the frame's (it read the future or a - // staging: world > S). - if (p.raise & MARK_AH && p.tx !== null && !seated(seat) && seat.ownWorld === WORLD_S) + // staging: world > S), or a member of the frame a held pass of that hold + // built (the held-frame clause; D-25: born in the hold's world, it reads + // plainly — a probe does not rescue it; D-27: its runs are the frame's, + // which commits with the hold). + if ( + p.raise & MARK_AH && + p.tx !== null && + !seated(seat) && + seat.ownWorld === WORLD_S && + !(seatBornInto(seat, p.tx) && seat.node!._config & CONFIG_HELD_FRAME) + ) seat.vhold = resolveTx(p.tx); if (p.raise & RAISE_VSEAT && p.tx !== null) { // (A lane the pass sat in links to the verdict lane, `enterLane`.) @@ -718,9 +727,15 @@ export function slot( // verdict lane's — the pass is the hold's verdict reader, unless its // branch exists only in the future (`creatorReads`: a pass whose // running creators, or itself when a memo, read the future or a - // staging — D-25, D-26, #4341). + // staging — D-25, D-26, #4341), or a member of the frame a held pass + // of the lane's hold built (the held-frame clause, D-25 D-27). const enter = vlane - ? inSeat || !(seat!.creatorsWorld > WORLD_S || (!isEffect && seat!.ownWorld > WORLD_S)) + ? inSeat || + !( + seat!.creatorsWorld > WORLD_S || + (!isEffect && seat!.ownWorld > WORLD_S) || + (seatBornInto(seat, l._parent!) && c!._config & CONFIG_HELD_FRAME) + ) ? RAISE_VSEAT : 0 : RAISE_LANE; diff --git a/packages/signals/src/core/verdict.ts b/packages/signals/src/core/verdict.ts index 0bb3c4075b..ee88e0ab08 100644 --- a/packages/signals/src/core/verdict.ts +++ b/packages/signals/src/core/verdict.ts @@ -14,6 +14,7 @@ import { CONFIG_GUESS, CONFIG_ASYNC, CONFIG_HELD, + CONFIG_HELD_FRAME, CONFIG_INPUTS_PUBLISHED, CONFIG_OVERRIDE, CONFIG_STAGED_ERROR, @@ -62,6 +63,7 @@ import { joinFuture, passLane, queuePendingNode, + resolveTx, setPassLane, stagedReaders, staleReader, @@ -94,10 +96,18 @@ function watchVerdict(c: Computed, unanswered = false): void { /** The reading pass is the holder's verdict lane's — unless already lane * work, or already the transaction's (it derives from the future — a held * node's, or the staging of a write this flush may hold — and the verdict - * does not rescue it: its result shows at the landing, re-derived). A lane + * does not rescue it: its result shows at the landing, re-derived), or a + * member of the frame a held pass of that hold built (CONFIG_HELD_FRAME, + * `bornInto`): the hold's own work, born in its world, reads plainly and + * its run is the frame's (D-25, D-27) — the same leaf reading a memo of the + * `latest()` waits for the landing too (`enterLane`; E2, #4284). A lane * read, for `recompute`'s tail (REACTIVE_LANE_READ). */ function route(c: Computed, t: Transaction): void { - if (!passLane && !(c._flags & (REACTIVE_JOINED | REACTIVE_STAGED_READ))) + if ( + !passLane && + !(c._flags & (REACTIVE_JOINED | REACTIVE_STAGED_READ)) && + !(c._config & CONFIG_HELD_FRAME && bornInto(c, resolveTx(t))) + ) setPassLane(verdictLane(t)); c._flags |= REACTIVE_LANE_READ; } diff --git a/packages/signals/tests/held-frame-verdict-parity.test.ts b/packages/signals/tests/held-frame-verdict-parity.test.ts new file mode 100644 index 0000000000..74123e6ea2 --- /dev/null +++ b/packages/signals/tests/held-frame-verdict-parity.test.ts @@ -0,0 +1,181 @@ +/** + * E2 / #4284 (memo wrapping and grouping never change the result) for a + * leaf in a held frame. ` 0}>` opened by an action holding + * `y`: the branch is that hold's frame (CONFIG_HELD_FRAME — a held pass + * built it), never on screen until the landing. A leaf in it reading the + * hold's display-ahead value — `latest(y)` inline, or a memo of it (a + * verdict-lane node) — re-runs on the hold's next step. + * + * Before, the inline leaf's `latest(y)` seated it as the hold's verdict + * reader (`route`), so its run went out with the verdict lane's reveal, + * while the same read through a memo was served the memo's staging as the + * hold's own work (`laneRead`'s L7' arm) and its run waited for the + * landing: `[10, 20]` beside `[10]`. A member of the frame a held pass of + * the hold built is the hold's own work, born in its world: it reads + * plainly and a probe does not rescue it (D-25, as #4426 for its reads); + * its runs are the frame's, which commits with the hold (D-27's joined + * pass, A29 ruling A). Every form now waits for the landing. + * + * The two-hold shape (the #4455 review): A holds `x`, `m = memo(latest(x) + * * 10)` is A's verdict lane's, B holds `y`, and `k` reads both — A merges + * into B. The leaf `[latest(y), m()]` inline, through a memo, or split into + * two leaves shows the same at every step. + */ +import { describe, expect, it } from "vitest"; +import { + action, + createMemo, + createRenderEffect, + createRoot, + createSignal, + flush, + latest +} from "../src/index.js"; + +const tick = async () => { + for (let i = 0; i < 6; i++) await Promise.resolve(); + flush(); +}; + +describe("a held frame's leaf over the hold's display-ahead value", () => { + async function single(form: "inline" | "memo inside" | "memo outside") { + const [y, setY] = createSignal(0); + let b1!: () => void, b2!: () => void; + const actB = action(function* () { + setY(1); + yield new Promise(r => (b1 = r)); + setY(2); + yield new Promise(r => (b2 = r)); + }); + const leaf: unknown[] = []; + let shown: unknown; + createRoot(() => { + const outside = createMemo(() => latest(y) * 10); + const when = createMemo(() => y() > 0); + const content = createMemo(() => { + if (!when()) return "off"; + const read = + form === "inline" + ? () => latest(y) * 10 + : form === "memo inside" + ? createMemo(() => latest(y) * 10) + : outside; + createRenderEffect(read, v => void leaf.push(v)); + return "on"; + }); + createRenderEffect(content, v => { + shown = v; + }); + }); + flush(); + const steps: unknown[] = []; + actB(); + await tick(); + steps.push([shown, ...leaf]); + b1(); + await tick(); + await tick(); + steps.push([shown, ...leaf]); + b2(); + await tick(); + await tick(); + steps.push([shown, ...leaf]); + return steps; + } + + const expected = [ + ["off", 10], + ["off", 10], + ["on", 10, 20] + ]; + for (const form of ["inline", "memo inside", "memo outside"] as const) + it(`one hold, ${form}: the leaf's run waits for the landing`, async () => { + expect(await single(form)).toEqual(expected); + }); + + async function merged(form: "inline" | "memo" | "split") { + const [x, setX] = createSignal(0); + const [y, setY] = createSignal(0); + let a1!: () => void, a2!: () => void, b1!: () => void; + const actA = action(function* () { + setX(1); + yield new Promise(r => (a1 = r)); + setX(2); + yield new Promise(r => (a2 = r)); + }); + const actB = action(function* () { + setY(1); + yield new Promise(r => (b1 = r)); + }); + let shownM: unknown, shown: unknown, leaf: unknown; + createRoot(() => { + const m = createMemo(() => latest(x) * 10); + const k = createMemo(() => x() + y()); + createRenderEffect(m, v => { + shownM = v; + }); + createRenderEffect(k, () => {}); + const when = createMemo(() => y() > 0); + const content = createMemo(() => { + if (!when()) return "off"; + if (form === "inline") + createRenderEffect( + () => `${latest(y)}/${m()}`, + v => { + leaf = v; + } + ); + else if (form === "memo") { + const mm = createMemo(() => `${latest(y)}/${m()}`); + createRenderEffect(mm, v => { + leaf = v; + }); + } else { + let ly: unknown, lm: unknown; + createRenderEffect( + () => latest(y), + v => { + ly = v; + leaf = `${ly}/${lm}`; + } + ); + createRenderEffect(m, v => { + lm = v; + leaf = `${ly}/${lm}`; + }); + } + return "on"; + }); + createRenderEffect(content, v => { + shown = v; + }); + }); + flush(); + const steps: unknown[] = []; + actA(); + await tick(); + actB(); + await tick(); + steps.push([shownM, shown, leaf]); + a1(); + await tick(); + await tick(); + steps.push([shownM, shown, leaf]); + a2(); + b1(); + await tick(); + await tick(); + steps.push([shownM, shown, leaf]); + return steps; + } + + const expectedMerged = [ + [10, "off", "1/10"], + [20, "off", "1/10"], + [20, "on", "1/20"] + ]; + for (const form of ["inline", "memo", "split"] as const) + it(`merged holds, ${form}: the same screens`, async () => { + expect(await merged(form)).toEqual(expectedMerged); + }); +}); diff --git a/packages/signals/tests/verdict-seat-merged-lane-4427.test.ts b/packages/signals/tests/verdict-seat-merged-lane-4427.test.ts index b0e1b8469f..d2488767a4 100644 --- a/packages/signals/tests/verdict-seat-merged-lane-4427.test.ts +++ b/packages/signals/tests/verdict-seat-merged-lane-4427.test.ts @@ -31,69 +31,79 @@ const tick = async () => { flush(); }; -it("a verdict reader seated in a hold reads a merged transaction's verdict lane as that hold's", async () => { - const [x, setX] = createSignal(0); - const [y, setY] = createSignal(0); - let a1!: () => void, a2!: () => void, b1!: () => void, b2!: () => void; - const actA = action(function* () { - setX(1); - yield new Promise(r => (a1 = r)); - setX(2); - yield new Promise(r => (a2 = r)); - }); - const actB = action(function* () { - setY(1); - yield new Promise(r => (b1 = r)); - setY(2); - yield new Promise(r => (b2 = r)); - }); - let shownM: unknown, leaf: unknown; - createRoot(() => { - const m = createMemo(() => latest(x) * 10); - const k = createMemo(() => x() + y()); - createRenderEffect(x, () => {}); - createRenderEffect(y, () => {}); - createRenderEffect(m, v => { - shownM = v; +// `mount`: `held` — ` 0}>`, the branch B's held pass +// built: the leaf is the hold's own work, born in its world (D-25, D-27), +// so `latest(y)` does not seat it and its runs wait with the frame for B's +// landing, inline as through a memo (held-frame-verdict-parity.test.ts). +// `latest` — ` 0}>`, a verdict reader's mount +// (mainline, D-27): the leaf is the verdict lanes' work and shows `m` with +// `m`. (Neither shape reaches the D-28 seat comparison any more: a held +// frame's leaf is never seated, and the mainline leaf's lane read enters +// A's lane either way.) +for (const mount of ["latest", "held"] as const) + it(`a verdict reader seated in a hold reads a merged transaction's verdict lane as that hold's (${mount} mount)`, async () => { + const [x, setX] = createSignal(0); + const [y, setY] = createSignal(0); + let a1!: () => void, a2!: () => void, b1!: () => void, b2!: () => void; + const actA = action(function* () { + setX(1); + yield new Promise(r => (a1 = r)); + setX(2); + yield new Promise(r => (a2 = r)); }); - createRenderEffect(k, () => {}); - // 0}>{[latest(y), m()]} - const when = createMemo(() => y() > 0); - const content = createMemo(() => { - if (!when()) return "off"; - createRenderEffect( - () => `${latest(y)}/${m()}`, - v => { - leaf = v; - } - ); - return "on"; + const actB = action(function* () { + setY(1); + yield new Promise(r => (b1 = r)); + setY(2); + yield new Promise(r => (b2 = r)); }); - createRenderEffect(content, () => {}); - }); - flush(); - actA(); - await tick(); - expect(shownM).toBe(10); - actB(); - await tick(); - expect(leaf).toBe("1/10"); + let shownM: unknown, leaf: unknown; + createRoot(() => { + const m = createMemo(() => latest(x) * 10); + const k = createMemo(() => x() + y()); + createRenderEffect(x, () => {}); + createRenderEffect(y, () => {}); + createRenderEffect(m, v => { + shownM = v; + }); + createRenderEffect(k, () => {}); + // 0 | y() > 0}>{[latest(y), m()]} + const when = createMemo(() => (mount === "latest" ? latest(y) : y()) > 0); + const content = createMemo(() => { + if (!when()) return "off"; + createRenderEffect( + () => `${latest(y)}/${m()}`, + v => { + leaf = v; + } + ); + return "on"; + }); + createRenderEffect(content, () => {}); + }); + flush(); + actA(); + await tick(); + expect(shownM).toBe(10); + actB(); + await tick(); + expect(leaf).toBe("1/10"); - // A's next step re-derives `m` in its (merged) verdict lane: the leaf - // shows it with `m`, not at B's landing. - a1(); - await tick(); - await tick(); - expect(shownM).toBe(20); - expect(leaf).toBe("1/20"); + // A's next step re-derives `m` in its (merged) verdict lane: the seated + // leaf shows it with `m`, not at B's landing; the held frame's waits. + a1(); + await tick(); + await tick(); + expect(shownM).toBe(20); + expect(leaf).toBe(mount === "latest" ? "1/20" : "1/10"); - b1(); - await tick(); - await tick(); - expect(leaf).toBe("2/20"); - b2(); - a2(); - await tick(); - await tick(); - expect([shownM, leaf]).toEqual([20, "2/20"]); -}); + b1(); + await tick(); + await tick(); + expect(leaf).toBe(mount === "latest" ? "2/20" : "1/10"); + b2(); + a2(); + await tick(); + await tick(); + expect([shownM, leaf]).toEqual([20, "2/20"]); + }); From d21baf5ad50f0692dd9727c72125e0343085e55c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 15:03:03 +0000 Subject: [PATCH 2/4] chore(size): record the held-frame verdict clause's cost on the lane pages Measured locally (linux) over next @ 131ceb8c. signals: + isPending/latest 11,125 B brotli / 30,704 B minified (+63 B), cap 11.12 -> 11.14 KB; page: compiled live server components 42,810 / 125,600 (+82 B), cap 42.73 -> 42.82 KB. Caps at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. page: live server components (frozen floor) +63 B minified, under its brotli cap (38,825 vs 38.85 KB): not raised. Every floor without the verdict engine is 0 B. (app: hydrating (no stores) is over its cap on next as well, unchanged here.) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2 --- scripts/size/scenarios.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/size/scenarios.js b/scripts/size/scenarios.js index 99c9d6c86f..6ff779ab0b 100644 --- a/scripts/size/scenarios.js +++ b/scripts/size/scenarios.js @@ -1443,9 +1443,10 @@ module.exports = [ // A probe beside `latest()` outside any Loading no longer loops on a refetch (F-6, D-23; 2026-10-30, over next @ 7135a77a): 11.07 KB -> 11.10 KB, recorded minified 30,492 -> 30,569 B (+77 B), measured locally (linux) at 11,085 B brotli. `pendingVerdict` remembers the transaction a `latest` read of an unheld flight opened, and a probe in it joins the verdict lane without asking to re-run at its landing (the re-run re-opened it every flush). Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // Batch re-record (2026-10-30, over next @ 563b6b0): cap unchanged, recorded minified 30,569 -> 30,596 B (+27 B), measured locally (linux) at 11,092 B brotli. Growth is the 2026-10-30 merges (#4454, #4457, #4461). Recorded minified = measured. // D-28's verdict-seat reset compares holds, not lane objects: a seated leaf reading a merged transaction's verdict lane stays the hold's verdict reader (`laneRead`) (#4427, #4455, 2026-10-30, over next @ cddaa76): 11.10 KB -> 11.12 KB, recorded minified 30,596 -> 30,641 B (+45 B), measured locally (linux) at 11,109 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. - limit: "11.12 KB", + // A held frame's leaf is the hold's own work, not its verdict reader: `route` and `enterLane`'s verdict arm leave a CONFIG_HELD_FRAME pass the frame's, so `latest()` inline and through a memo wait for the landing alike (E2, D-25, D-27; 2026-10-30, over next @ 131ceb8c): 11.12 KB -> 11.14 KB, recorded minified 30,641 -> 30,704 B (+63 B), measured locally (linux) at 11,125 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + limit: "11.14 KB", // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 28,693 -> 29,086 B (+343 B minified over next), measured locally (linux) at 10,565 B brotli (+135 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 30641, + capMinified: 30704, alias }, { @@ -5927,11 +5928,12 @@ module.exports = [ // A probe beside `latest()` outside any Loading no longer loops on a refetch (F-6, D-23; 2026-10-30, over next @ 7135a77a): 42.67 KB -> 42.71 KB, recorded minified 125,374 -> 125,450 B (+76 B), measured locally (linux) at 42,693 B brotli. `pendingVerdict` remembers the transaction a `latest` read of an unheld flight opened, and a probe in it joins the verdict lane without asking to re-run at its landing (the re-run re-opened it every flush). Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // Batch re-record (2026-10-30, over next @ 563b6b0): cap unchanged, recorded minified 125,450 -> 125,478 B (+28 B), measured locally (linux) at 42,695 B brotli. Growth is the 2026-10-30 merges (#4454, #4457, #4461). Recorded minified = measured. // D-28's verdict-seat reset compares holds, not lane objects: a seated leaf reading a merged transaction's verdict lane stays the hold's verdict reader (`laneRead`) (#4427, #4455, 2026-10-30, over next @ cddaa76): 42.71 KB -> 42.73 KB, recorded minified 125,478 -> 125,518 B (+40 B), measured locally (linux) at 42,715 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. - limit: "42.73 KB", + // A held frame's leaf is the hold's own work, not its verdict reader: `route` and `enterLane`'s verdict arm leave a CONFIG_HELD_FRAME pass the frame's, so `latest()` inline and through a memo wait for the landing alike (E2, D-25, D-27; 2026-10-30, over next @ 131ceb8c): 42.73 KB -> 42.82 KB, recorded minified 125,518 -> 125,600 B (+82 B), measured locally (linux) at 42,810 B brotli (+95 B, mostly layout). Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + limit: "42.82 KB", // An Errored heals when the last reader that caught its error is disposed (#4373, #4384, 2026-10-28, re-recorded over next @ cbc0eebd): recorded minified 123,191 -> 123,249 B (+58 B minified over next's record), measured locally (linux) at 41,899 B brotli. Recorded minified = measured; CI re-bases. // Boundary readers keyed by the source they wait on (#4373), with enterLane's tail folded into one else-chain as an offset (-29 B on lane pages) (#4384, 2026-10-28, re-recorded over next @ 1b32ff2e): recorded minified 123,203 -> 123,224 B (+21 B minified over next's record), measured locally (linux) at 41,966 B brotli. Recorded minified = measured; CI re-bases. // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 123,224 -> 123,733 B (+403 B minified over next), measured locally (linux) at 42,119 B brotli (+169 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 125518, + capMinified: 125600, alias: pageAlias }, { From 4ec50e3b88e48d3f7700dce35bbc8973d1df4e58 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 16:18:14 +0000 Subject: [PATCH 3/4] refactor(signals): drop #4455's held-hold comparison in laneRead; the held-frame clause covers it laneRead's D-28 seat reset goes back to comparing verdict lanes by identity. With the held-frame clause, no shape depends on the hold comparison, and the seat table's #4427 known entry no longer matches anything. -48 B minified on the verdict pages. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2 --- packages/signals/src/core/lanes.ts | 12 +++--------- packages/signals/src/core/seat.ts | 22 ---------------------- scripts/size/scenarios.js | 10 +++++----- 3 files changed, 8 insertions(+), 36 deletions(-) diff --git a/packages/signals/src/core/lanes.ts b/packages/signals/src/core/lanes.ts index 0ba115d99d..483e06fa22 100644 --- a/packages/signals/src/core/lanes.ts +++ b/packages/signals/src/core/lanes.ts @@ -723,17 +723,11 @@ export function laneRead(c: Computed | null, el: Signal | Computed { - const l = el!._x?._transaction; - return ( - (c as any)._type === EFFECT_RENDER && - seat.vhold !== null && - !!l && - l._lane && - laneOf(l) === null && - l._parent !== null && - resolveTx(l._parent) !== l._parent && - resolveTx(l._parent) === resolveTx(seat.vhold) - ); - } - }, { // `recompute`'s born-held test reads `creatorPass(oldcontext)`'s JOINED // flag — the owner context of the creation, not the running pass. Under diff --git a/scripts/size/scenarios.js b/scripts/size/scenarios.js index 939a43ac76..a9a4ca6ca1 100644 --- a/scripts/size/scenarios.js +++ b/scripts/size/scenarios.js @@ -1443,10 +1443,10 @@ module.exports = [ // A probe beside `latest()` outside any Loading no longer loops on a refetch (F-6, D-23; 2026-10-30, over next @ 7135a77a): 11.07 KB -> 11.10 KB, recorded minified 30,492 -> 30,569 B (+77 B), measured locally (linux) at 11,085 B brotli. `pendingVerdict` remembers the transaction a `latest` read of an unheld flight opened, and a probe in it joins the verdict lane without asking to re-run at its landing (the re-run re-opened it every flush). Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // Batch re-record (2026-10-30, over next @ 563b6b0): cap unchanged, recorded minified 30,569 -> 30,596 B (+27 B), measured locally (linux) at 11,092 B brotli. Growth is the 2026-10-30 merges (#4454, #4457, #4461). Recorded minified = measured. // D-28's verdict-seat reset compares holds, not lane objects: a seated leaf reading a merged transaction's verdict lane stays the hold's verdict reader (`laneRead`) (#4427, #4455, 2026-10-30, over next @ cddaa76): 11.10 KB -> 11.12 KB, recorded minified 30,596 -> 30,641 B (+45 B), measured locally (linux) at 11,109 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. - // A held frame's leaf is the hold's own work, not its verdict reader: `route` and `enterLane`'s verdict arm leave a CONFIG_HELD_FRAME pass the frame's, so `latest()` inline and through a memo wait for the landing alike (E2, D-25, D-27; 2026-10-30, over next @ 131ceb8c): 11.12 KB -> 11.14 KB, recorded minified 30,641 -> 30,704 B (+63 B), measured locally (linux) at 11,125 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. - limit: "11.14 KB", + // A held frame's leaf is the hold's own work, not its verdict reader (E2; D-25, D-27; 2026-10-30, over next @ ab3d2add): cap unchanged at 11.12 KB, recorded minified 30,641 -> 30,671 B (+30 B), measured locally (linux) at 11,113 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + limit: "11.12 KB", // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 28,693 -> 29,086 B (+343 B minified over next), measured locally (linux) at 10,565 B brotli (+135 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 30704, + capMinified: 30671, alias }, { @@ -5929,12 +5929,12 @@ module.exports = [ // A probe beside `latest()` outside any Loading no longer loops on a refetch (F-6, D-23; 2026-10-30, over next @ 7135a77a): 42.67 KB -> 42.71 KB, recorded minified 125,374 -> 125,450 B (+76 B), measured locally (linux) at 42,693 B brotli. `pendingVerdict` remembers the transaction a `latest` read of an unheld flight opened, and a probe in it joins the verdict lane without asking to re-run at its landing (the re-run re-opened it every flush). Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // Batch re-record (2026-10-30, over next @ 563b6b0): cap unchanged, recorded minified 125,450 -> 125,478 B (+28 B), measured locally (linux) at 42,695 B brotli. Growth is the 2026-10-30 merges (#4454, #4457, #4461). Recorded minified = measured. // D-28's verdict-seat reset compares holds, not lane objects: a seated leaf reading a merged transaction's verdict lane stays the hold's verdict reader (`laneRead`) (#4427, #4455, 2026-10-30, over next @ cddaa76): 42.71 KB -> 42.73 KB, recorded minified 125,478 -> 125,518 B (+40 B), measured locally (linux) at 42,715 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. - // A held frame's leaf is the hold's own work, not its verdict reader: `route` and `enterLane`'s verdict arm leave a CONFIG_HELD_FRAME pass the frame's, so `latest()` inline and through a memo wait for the landing alike (E2, D-25, D-27; 2026-10-30, over next @ 131ceb8c): 42.73 KB -> 42.82 KB, recorded minified 125,518 -> 125,600 B (+82 B), measured locally (linux) at 42,810 B brotli (+95 B, mostly layout). Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + // A held frame's leaf is the hold's own work, not its verdict reader (E2; D-25, D-27; 2026-10-30, over next @ ab3d2add): 42.73 KB -> 42.82 KB, recorded minified 125,518 -> 125,567 B (+49 B), measured locally (linux) at 42,801 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. limit: "42.82 KB", // An Errored heals when the last reader that caught its error is disposed (#4373, #4384, 2026-10-28, re-recorded over next @ cbc0eebd): recorded minified 123,191 -> 123,249 B (+58 B minified over next's record), measured locally (linux) at 41,899 B brotli. Recorded minified = measured; CI re-bases. // Boundary readers keyed by the source they wait on (#4373), with enterLane's tail folded into one else-chain as an offset (-29 B on lane pages) (#4384, 2026-10-28, re-recorded over next @ 1b32ff2e): recorded minified 123,203 -> 123,224 B (+21 B minified over next's record), measured locally (linux) at 41,966 B brotli. Recorded minified = measured; CI re-bases. // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 123,224 -> 123,733 B (+403 B minified over next), measured locally (linux) at 42,119 B brotli (+169 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 125600, + capMinified: 125567, alias: pageAlias }, { From 20f694f756076f57862254ed2c76754b371da8d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 18:29:48 +0000 Subject: [PATCH 4/4] chore(size): re-record over next @ d0fc2851 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015hPxMkC3jg3Uivh65gvaf2 --- scripts/size/scenarios.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/size/scenarios.js b/scripts/size/scenarios.js index 7bcbb47f12..e9ff592079 100644 --- a/scripts/size/scenarios.js +++ b/scripts/size/scenarios.js @@ -1446,9 +1446,10 @@ module.exports = [ // A staged error reaches the memos and derived stores that derive from it (#4456, 2026-10-30, re-measured over next @ b773146): 11.12 KB -> 11.17 KB, recorded minified 30,641 -> 30,771 B (+130 B), measured locally (linux) at 11,153 B brotli. The settle walk marks a derivation of a staged error with it, and a derived store's family hears it (D-41), with the verdict engine alone. Correctness; Size-Exception in #4456. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // A verdict reader born into a hold joins it at its re-pass (#4471, #4467, 2026-10-30, re-measured over next @ 749b0d7): cap unchanged at 11.17 KB, recorded minified 30,771 -> 30,800 B (+29 B), measured locally (linux) at 11,166 B brotli. Correctness (D-25, D-13); Size-Exception in #4471 for the floor. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // A derived store with no live leaf skips its flight's observe (#4479, 2026-10-30, re-measured over next @ 663ecb0): 11.17 KB -> 11.19 KB, recorded minified 30,800 -> 30,822 B (+22 B), measured locally (linux) at 11,177 B brotli. Correctness (F-3, D-11); Size-Exception in #4479 for the floor. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + // A held frame's leaf is the hold's own work (E2, 2026-10-30, over next @ d0fc2851): cap unchanged at 11.19 KB, recorded minified 30,822 -> 30,837 B (+15 B), measured locally (linux) at 11,181 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. limit: "11.19 KB", // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 28,693 -> 29,086 B (+343 B minified over next), measured locally (linux) at 10,565 B brotli (+135 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 30822, + capMinified: 30837, alias }, { @@ -5939,11 +5940,12 @@ module.exports = [ // A staged error reaches the memos and derived stores that derive from it (#4456, 2026-10-30, re-measured over next @ b773146): 42.75 KB -> 42.79 KB, recorded minified 125,540 -> 125,655 B (+115 B), measured locally (linux) at 42,777 B brotli. The settle walk marks a derivation of a staged error with it, and a derived store's family hears it (D-41), with the verdict engine alone. Correctness; Size-Exception in #4456. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // A verdict reader born into a hold joins it at its re-pass (#4471, #4467, 2026-10-30, re-measured over next @ 749b0d7): 42.79 KB -> 42.83 KB, recorded minified 125,655 -> 125,684 B (+29 B), measured locally (linux) at 42,817 B brotli. Correctness (D-25, D-13); Size-Exception in #4471 for the floor. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // A derived store with no live leaf skips its flight's observe (#4479, 2026-10-30, re-measured over next @ 663ecb0): cap unchanged at 42.83 KB, recorded minified 125,684 -> 125,706 B (+22 B), measured locally (linux) at 42,822 B brotli. Correctness (F-3, D-11); Size-Exception in #4479 for the floor. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. - limit: "42.83 KB", + // A held frame's leaf is the hold's own work (E2, 2026-10-30, over next @ d0fc2851): 42.83 KB -> 42.85 KB, recorded minified 125,706 -> 125,747 B (+41 B), measured locally (linux) at 42,840 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + limit: "42.85 KB", // An Errored heals when the last reader that caught its error is disposed (#4373, #4384, 2026-10-28, re-recorded over next @ cbc0eebd): recorded minified 123,191 -> 123,249 B (+58 B minified over next's record), measured locally (linux) at 41,899 B brotli. Recorded minified = measured; CI re-bases. // Boundary readers keyed by the source they wait on (#4373), with enterLane's tail folded into one else-chain as an offset (-29 B on lane pages) (#4384, 2026-10-28, re-recorded over next @ 1b32ff2e): recorded minified 123,203 -> 123,224 B (+21 B minified over next's record), measured locally (linux) at 41,966 B brotli. Recorded minified = measured; CI re-bases. // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 123,224 -> 123,733 B (+403 B minified over next), measured locally (linux) at 42,119 B brotli (+169 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 125706, + capMinified: 125747, alias: pageAlias }, { @@ -6348,11 +6350,12 @@ module.exports = [ // A staged error reaches the memos and derived stores that derive from it (#4456, 2026-10-30, re-measured over next @ b773146): 48.44 KB -> 48.51 KB, recorded minified 142,780 -> 142,918 B (+138 B), measured locally (linux) at 48,498 B brotli. The settle walk marks a derivation of a staged error with it, and a derived store's family hears it (D-41), with the verdict engine alone. Correctness; Size-Exception in #4456. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // A verdict reader born into a hold joins it at its re-pass (#4471, #4467, 2026-10-30, re-measured over next @ 749b0d7): cap unchanged at 48.51 KB, recorded minified 142,918 -> 142,947 B (+29 B), measured locally (linux) at 48,462 B brotli. Correctness (D-25, D-13); Size-Exception in #4471 for the floor. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. // A derived store with no live leaf skips its flight's observe (#4479, 2026-10-30, re-measured over next @ 663ecb0): cap unchanged at 48.51 KB, recorded minified 142,947 -> 142,969 B (+22 B), measured locally (linux) at 48,496 B brotli. Correctness (F-3, D-11); Size-Exception in #4479 for the floor. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. + // A held frame's leaf is the hold's own work (E2, 2026-10-30, over next @ d0fc2851): cap unchanged at 48.51 KB, recorded minified 142,969 -> 143,001 B (+32 B), measured locally (linux) at 48,473 B brotli. Correctness. Cap at measured + 10 B rounded up to 0.01 KB; recorded minified = measured. limit: "48.51 KB", // An Errored heals when the last reader that caught its error is disposed (#4373, #4384, 2026-10-28, re-recorded over next @ cbc0eebd): recorded minified 140,451 -> 140,509 B (+58 B minified over next's record), measured locally (linux) at 47,516 B brotli. Recorded minified = measured; CI re-bases. // Boundary readers keyed by the source they wait on (#4373), with enterLane's tail folded into one else-chain as an offset (-29 B on lane pages) (#4384, 2026-10-28, re-recorded over next @ 1b32ff2e): recorded minified 140,463 -> 140,485 B (+22 B minified over next's record), measured locally (linux) at 47,547 B brotli. Recorded minified = measured; CI re-bases. // latest() read inline and through a memo show the same screen (#4284 through a memo; a plain write beside an async memo), 2026-10-29, over next @ 7ebd4a32: recorded minified 140,485 -> 140,983 B (+405 B minified over next), measured locally (linux) at 47,722 B brotli (+162 B over next). A render effect a verdict memo's change re-runs reads as its verdict reader for that pass (`laneDirty`), a pass that read a staging before the frame had a transaction re-derives once as a verdict reader only if the frame parks, `latest()` of a first load in flight in a verdict lane is loading (also through an identity memo, a derived store and `isPending`), a lane's dissolution leaves such a load and the nodes pending on it uninitialized instead of committing `undefined`, a verdict lane born at a seam is judged at it, a pass born in a staged reader stays the frame's on a verdict-memo read (C4, #4010), a plain write beside `latest()` computes once (the seam re-derives a pre-transaction staged reader only if the frame parks), a verdict reader's plain read of a staging in a transaction only a `latest()` opened is the frame's read, so a memo of `latest()` computes once too (D-22; not a pass with no value yet, D-6), and an error stays the display while the memo it came through re-asks, a Loading fallback behind it included (D-39, async-gen 91501 #1831). recompute's CONFIG_VERDICT clear now sits behind the lane engine: -21 B minified on every floor. Correctness; the maintainer: "only flag me if brotli goes more than 20kb" (2026-10-29). Cap unchanged; recorded minified = measured. - capMinified: 142969, + capMinified: 143001, alias: pageAlias, conditions: solidConditions, compile: { hydratable: true }