Repository navigation
fix(signals): hold conditional reveals on existing async work - #3305
Conversation
🦋 Changeset detectedLatest commit: 98d457f The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 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 |
29cacdb to
6ea30eb
Compare
…lError branch Same semantics, fewer bytes: the new check and the reporter registration share one actualError test, read the module-level currentBatch instead of this._batch, and the error fallback is `??` (every caller passes nothing or this node's own _x._error, so a null falls back to the same null). Measured against next: signals + createStore 14358 B brotli, under both the cap and the pre-PR baseline; the PR as written was 18 B over on Linux. Co-authored-by: Cursor <[email protected]>
6ea30eb to
98d457f
Compare
|
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…unless its inputs are visible; same-value re-prediction renews provenance (A15 re-rule, #3331) Review on #3347 (GabbeV). Two fixes and a re-ruling. A15 reveal corollary, re-ruled: #3334 removed read()'s pending-branch carve-out outright — a stale (render) reader of a node pending in another transaction always held on the flight. That made a new reader of a memo whose input write is ITSELF still held wait for the landing, though showing the committed pair introduces no inconsistency (parallel transactions; effects don't entangle; React 19.3 stopped entangling the same shape). The carve-out returns, gated on input visibility: the reader shows committed, does not entangle, and is recorded for the transaction's commit replay (heldFromStale) — refused, holding instead, when the committed value would tear against the frame: the flight's inputs were PUBLISHED while it was pending (CONFIG_INPUTS_PUBLISHED, set by commitPendingNode's computed branch when a commit leaves the node in the air, #3305; cleared by notifyStatus when the node next enters pending from a settled state), the node rides a live lane (GlobalQueue._laneLive -> resolveLane, exact rather than sticky; optimistic / latest, #3334), or the node is uninitialized. The initialized-memo pin and its store twin return to "show v0, then v1". Replay hygiene the carve-out surfaced: an effect recorded in _gatedSubs that later recomputes UNDER the recording transaction sees its staged view and is applied by the commit (ownership) — the stale recording published the frame twice. recompute drops it at its start; a lane's committed-view read re-records during the run, so the lane replay is untouched. Provenance (#3331 follow-up): a same-value optimistic write by a newer action took the fast path — entangling the transaction — without renewing _overrideStamp, so the OLDER action's slow source superseded a value the user had just re-confirmed: a corrective downstream refetch and a pending flip for nothing. The fast path now renews the stamp to a newer origin. Pinned: tests/reveal-carve-out.test.ts (GabbeV's "revealed reader never catches up" and "conditional reader stays hidden" shapes, a replacement flight over published inputs, a retired lane), the same-value provenance twin in spec-async-semantics. SPEC A15 + re-ruling log, INTERNALS §3. Core floor 22,638 -> 22,737 (conscious). Size-limit scenarios reconciled for the lane-authority stack with per-scenario notes. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…unless its inputs are visible; same-value re-prediction renews provenance (A15 re-rule, #3331) Review on #3347 (GabbeV). Two fixes and a re-ruling. A15 reveal corollary, re-ruled: #3334 removed read()'s pending-branch carve-out outright — a stale (render) reader of a node pending in another transaction always held on the flight. That made a new reader of a memo whose input write is ITSELF still held wait for the landing, though showing the committed pair introduces no inconsistency (parallel transactions; effects don't entangle; React 19.3 stopped entangling the same shape). The carve-out returns, gated on input visibility: the reader shows committed, does not entangle, and is recorded for the transaction's commit replay (heldFromStale) — refused, holding instead, when the committed value would tear against the frame: the flight's inputs were PUBLISHED while it was pending (CONFIG_INPUTS_PUBLISHED, set by commitPendingNode's computed branch when a commit leaves the node in the air, #3305; cleared by notifyStatus when the node next enters pending from a settled state), the node rides a live lane (GlobalQueue._laneLive -> resolveLane, exact rather than sticky; optimistic / latest, #3334), or the node is uninitialized. The initialized-memo pin and its store twin return to "show v0, then v1". Replay hygiene the carve-out surfaced: an effect recorded in _gatedSubs that later recomputes UNDER the recording transaction sees its staged view and is applied by the commit (ownership) — the stale recording published the frame twice. recompute drops it at its start; a lane's committed-view read re-records during the run, so the lane replay is untouched. Provenance (#3331 follow-up): a same-value optimistic write by a newer action took the fast path — entangling the transaction — without renewing _overrideStamp, so the OLDER action's slow source superseded a value the user had just re-confirmed: a corrective downstream refetch and a pending flip for nothing. The fast path now renews the stamp to a newer origin. Pinned: tests/reveal-carve-out.test.ts (GabbeV's "revealed reader never catches up" and "conditional reader stays hidden" shapes, a replacement flight over published inputs, a retired lane), the same-value provenance twin in spec-async-semantics. SPEC A15 + re-ruling log, INTERNALS §3. Core floor 22,638 -> 22,737 (conscious). Size-limit scenarios reconciled for the lane-authority stack with per-scenario notes. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…unless its inputs are visible; same-value re-prediction renews provenance (A15 re-rule, #3331) Review on #3347 (GabbeV). Two fixes and a re-ruling. A15 reveal corollary, re-ruled: #3334 removed read()'s pending-branch carve-out outright — a stale (render) reader of a node pending in another transaction always held on the flight. That made a new reader of a memo whose input write is ITSELF still held wait for the landing, though showing the committed pair introduces no inconsistency (parallel transactions; effects don't entangle; React 19.3 stopped entangling the same shape). The carve-out returns, gated on input visibility: the reader shows committed, does not entangle, and is recorded for the transaction's commit replay (heldFromStale) — refused, holding instead, when the committed value would tear against the frame: the flight's inputs were PUBLISHED while it was pending (CONFIG_INPUTS_PUBLISHED, set by commitPendingNode's computed branch when a commit leaves the node in the air, #3305; cleared by notifyStatus when the node next enters pending from a settled state), the node rides a live lane (GlobalQueue._laneLive -> resolveLane, exact rather than sticky; optimistic / latest, #3334), or the node is uninitialized. The initialized-memo pin and its store twin return to "show v0, then v1". Replay hygiene the carve-out surfaced: an effect recorded in _gatedSubs that later recomputes UNDER the recording transaction sees its staged view and is applied by the commit (ownership) — the stale recording published the frame twice. recompute drops it at its start; a lane's committed-view read re-records during the run, so the lane replay is untouched. Provenance (#3331 follow-up): a same-value optimistic write by a newer action took the fast path — entangling the transaction — without renewing _overrideStamp, so the OLDER action's slow source superseded a value the user had just re-confirmed: a corrective downstream refetch and a pending flip for nothing. The fast path now renews the stamp to a newer origin. Pinned: tests/reveal-carve-out.test.ts (GabbeV's "revealed reader never catches up" and "conditional reader stays hidden" shapes, a replacement flight over published inputs, a retired lane), the same-value provenance twin in spec-async-semantics. SPEC A15 + re-ruling log, INTERNALS §3. Core floor 22,638 -> 22,737 (conscious). Size-limit scenarios reconciled for the lane-authority stack with per-scenario notes. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…unless its inputs are visible; same-value re-prediction renews provenance (A15 re-rule, #3331) Review on #3347 (GabbeV). Two fixes and a re-ruling. A15 reveal corollary, re-ruled: #3334 removed read()'s pending-branch carve-out outright — a stale (render) reader of a node pending in another transaction always held on the flight. That made a new reader of a memo whose input write is ITSELF still held wait for the landing, though showing the committed pair introduces no inconsistency (parallel transactions; effects don't entangle; React 19.3 stopped entangling the same shape). The carve-out returns, gated on input visibility: the reader shows committed, does not entangle, and is recorded for the transaction's commit replay (heldFromStale) — refused, holding instead, when the committed value would tear against the frame: the flight's inputs were PUBLISHED while it was pending (CONFIG_INPUTS_PUBLISHED, set by commitPendingNode's computed branch when a commit leaves the node in the air, #3305; cleared by notifyStatus when the node next enters pending from a settled state), the node rides a live lane (GlobalQueue._laneLive -> resolveLane, exact rather than sticky; optimistic / latest, #3334), or the node is uninitialized. The initialized-memo pin and its store twin return to "show v0, then v1". Replay hygiene the carve-out surfaced: an effect recorded in _gatedSubs that later recomputes UNDER the recording transaction sees its staged view and is applied by the commit (ownership) — the stale recording published the frame twice. recompute drops it at its start; a lane's committed-view read re-records during the run, so the lane replay is untouched. Provenance (#3331 follow-up): a same-value optimistic write by a newer action took the fast path — entangling the transaction — without renewing _overrideStamp, so the OLDER action's slow source superseded a value the user had just re-confirmed: a corrective downstream refetch and a pending flip for nothing. The fast path now renews the stamp to a newer origin. Pinned: tests/reveal-carve-out.test.ts (GabbeV's "revealed reader never catches up" and "conditional reader stays hidden" shapes, a replacement flight over published inputs, a retired lane), the same-value provenance twin in spec-async-semantics. SPEC A15 + re-ruling log, INTERNALS §3. Core floor 22,638 -> 22,737 (conscious). Size-limit scenarios reconciled for the lane-authority stack with per-scenario notes. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…unless its inputs are visible; same-value re-prediction renews provenance (A15 re-rule, #3331) Review on #3347 (GabbeV). Two fixes and a re-ruling. A15 reveal corollary, re-ruled: #3334 removed read()'s pending-branch carve-out outright — a stale (render) reader of a node pending in another transaction always held on the flight. That made a new reader of a memo whose input write is ITSELF still held wait for the landing, though showing the committed pair introduces no inconsistency (parallel transactions; effects don't entangle; React 19.3 stopped entangling the same shape). The carve-out returns, gated on input visibility: the reader shows committed, does not entangle, and is recorded for the transaction's commit replay (heldFromStale) — refused, holding instead, when the committed value would tear against the frame: the flight's inputs were PUBLISHED while it was pending (CONFIG_INPUTS_PUBLISHED, set by commitPendingNode's computed branch when a commit leaves the node in the air, #3305; cleared by notifyStatus when the node next enters pending from a settled state), the node rides a live lane (GlobalQueue._laneLive -> resolveLane, exact rather than sticky; optimistic / latest, #3334), or the node is uninitialized. The initialized-memo pin and its store twin return to "show v0, then v1". Replay hygiene the carve-out surfaced: an effect recorded in _gatedSubs that later recomputes UNDER the recording transaction sees its staged view and is applied by the commit (ownership) — the stale recording published the frame twice. recompute drops it at its start; a lane's committed-view read re-records during the run, so the lane replay is untouched. Provenance (#3331 follow-up): a same-value optimistic write by a newer action took the fast path — entangling the transaction — without renewing _overrideStamp, so the OLDER action's slow source superseded a value the user had just re-confirmed: a corrective downstream refetch and a pending flip for nothing. The fast path now renews the stamp to a newer origin. Pinned: tests/reveal-carve-out.test.ts (GabbeV's "revealed reader never catches up" and "conditional reader stays hidden" shapes, a replacement flight over published inputs, a retired lane), the same-value provenance twin in spec-async-semantics. SPEC A15 + re-ruling log, INTERNALS §3. Core floor 22,638 -> 22,737 (conscious). Size-limit scenarios reconciled for the lane-authority stack with per-scenario notes. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…ess of stamp (#3334) Two halves of one tear. `read()`'s pending branch let a stale (render) reader of another transaction carve out a node pending in a foreign transaction and show its committed value — on the theory that the stamp meant that transaction also held the node's inputs. It does not: the stamp is pending-node bookkeeping, and the inputs may already be on screen (committed #3305, lane-revealed #3334). A render reader landing on a pending node now throws whichever transaction the node is stamped with (A15: observed async settles as one unit). And `handleAsync`'s settle-time re-entry entered the lane owner's transaction for a lane-routed landing, folding every transaction waiting on the flight into the owner's action — a reveal that discovered the flight then waited on the action instead of on the flight. It enters the waiter: the transaction whose blocker this landing clears (`waitingTransition`). Pinned in spec A15 (#3334 describe) and tests/stale-read-uninitialized-cross-transition.test.ts (re-expected). INTERNALS §3. Co-authored-by: Claude via Cursor <[email protected]>
…unless its inputs are visible; same-value re-prediction renews provenance (A15 re-rule, #3331) Review on #3347 (GabbeV). Two fixes and a re-ruling. A15 reveal corollary, re-ruled: #3334 removed read()'s pending-branch carve-out outright — a stale (render) reader of a node pending in another transaction always held on the flight. That made a new reader of a memo whose input write is ITSELF still held wait for the landing, though showing the committed pair introduces no inconsistency (parallel transactions; effects don't entangle; React 19.3 stopped entangling the same shape). The carve-out returns, gated on input visibility: the reader shows committed, does not entangle, and is recorded for the transaction's commit replay (heldFromStale) — refused, holding instead, when the committed value would tear against the frame: the flight's inputs were PUBLISHED while it was pending (CONFIG_INPUTS_PUBLISHED, set by commitPendingNode's computed branch when a commit leaves the node in the air, #3305; cleared by notifyStatus when the node next enters pending from a settled state), the node rides a live lane (GlobalQueue._laneLive -> resolveLane, exact rather than sticky; optimistic / latest, #3334), or the node is uninitialized. The initialized-memo pin and its store twin return to "show v0, then v1". Replay hygiene the carve-out surfaced: an effect recorded in _gatedSubs that later recomputes UNDER the recording transaction sees its staged view and is applied by the commit (ownership) — the stale recording published the frame twice. recompute drops it at its start; a lane's committed-view read re-records during the run, so the lane replay is untouched. Provenance (#3331 follow-up): a same-value optimistic write by a newer action took the fast path — entangling the transaction — without renewing _overrideStamp, so the OLDER action's slow source superseded a value the user had just re-confirmed: a corrective downstream refetch and a pending flip for nothing. The fast path now renews the stamp to a newer origin. Pinned: tests/reveal-carve-out.test.ts (GabbeV's "revealed reader never catches up" and "conditional reader stays hidden" shapes, a replacement flight over published inputs, a retired lane), the same-value provenance twin in spec-async-semantics. SPEC A15 + re-ruling log, INTERNALS §3. Core floor 22,638 -> 22,737 (conscious). Size-limit scenarios reconciled for the lane-authority stack with per-scenario notes. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…node in a held frame stays the lane's; a verdict reader revealing an orphan flight holds it (#3798) * fix(signals): a lane's node inside a held frame stays the lane's (fuzzer F7a/F7b) `holdFrame` holds a parked pass's frame with the transaction (ruling A). It re-listed a lane's node found there — a verdict reader created in the frame, broken out into the holder's verdict lane (display-ahead, L2 rule 6), or a derivation of a guess — on the frame's transaction, still carrying its lane value (CONFIG_OVERRIDE). At the landing `dissolveLane` no longer found the node (its `_transaction` was the transaction's) and `land` nulled the transaction: a lane node with no lane, and the landing's re-derivation tripped over it (`laneRead` → `txOf(null)` → TypeError, REACTIVITY_HALTED). The shapes: a `Loading` whose content reads `latest(x)`, unmounted and remounted while `x` is held by an action (F7a); a memo of `isPending(() => x())` mounted in the tick of the write it probes, its mount toggled off and on while the write is held (F7b). The remounting gate's write joins the hold (A34 (1)), so its new frame is held with it — and the verdict-lane nodes inside it were taken along. `holdFrame` now skips a child listed on a lane, as the seam's own hold loop already does for this flush's stagings: lane work never makes its node transaction work (A15, #3698), and a lane pass's frame is the lane's, revealed and retired at its seam. The lane's end (`dissolveLane` at the parent's landing) commits the node as before. Every other `holdNode` site (the seam loop, the store's three) already excluded lane work; this was the one that did not. F7a and F7b flip from `it.fails` to `it`. No other pin moved. Co-authored-by: Claude via Cursor <[email protected]> * fix(signals): a verdict reader revealing a flight nobody holds registers it with the frame (fuzzer F12) A verdict reader (`latest`/`isPending` in its pass) that plainly reads a pending node is served the committed value and `observeFlight`s it: the frame holds, the reader is the holder's verdict lane's, and it re-derives at the landing (REACTIVE_FRAME_READ — a blocker of the hold through the flight's subscribers, `blockedBy`). That hold is on the flight's node: a reader served committed never goes pending, so the transaction waits only through the node it holds. A flight that went pending this flush is queued for the seam to hold; one in the air from before and held by nobody was not — the transaction opened with no entry, landed at its own seam, and its `_reruns` re-derived the reader into the same observation, every flush ("Potential Infinite Loop Detected"). The fuzzer's shape (F12): an action whose body ends with `setSource(1)`, `setShow(true)` adopted in the action's tick (O1), a reader of `[latest(source), node()]` over an async memo of `latest(source)`. At the body's end the memo re-asks as the action's verdict lane's work (the proposal) while the reader, a stale reader of the held `show`, shows "hidden"; nothing displays the flight, the action lands (A29: a flight nobody renders holds nothing), `dissolveLane` commits the memo beneath its flight, and the landing's rerun reveals the orphan flight to the verdict reader. Reduced: any memo re-asked unobserved (its inputs commit, #3305) then revealed to a `latest()` reader did the same. `observeFlight` now queues the flight's node for the seam when nobody holds it, as if it had gone pending here (A15 first observer, #3458: "the observation registers it, and the transaction waits on the flight it now shows a reader of"); the seam applies its own hold rules (a loading source is nobody's frame, A34 (2), `holdFrame`). The landing then resumes that transaction through `setSignal`'s join and the reader re-derives once. The display follows the existing rules: a reveal that read a staging stays the frame's and waits with the flight (rule 3, A15 reveal corollary — the reduced pin asserts `"hidden"` → `[1,1]`); a verdict reader with nothing staged shows the screen ahead (rule 6). F12 flips from `it.fails` to `it`; a reduced pin without the action or lane is added beside it. No other pin moved. Co-authored-by: Claude via Cursor <[email protected]> * chore(size): raise three caps for the fuzzer F7/F12 fixes (Size-Exception) Raises only the caps the two fixes push over, each set to measured + 10 B rounded up to 0.01 KB, with dated ledger notes in scenarios.js: - signals: + isPending/latest 9.45 -> 9.47 KB (9,456 B; was 6 B over) - page: base server components 44.78 -> 44.84 KB (44,829 B; was 49 B over) - page: live server components 48.45 -> 48.47 KB (48,454 B; was 4 B over) Attributable delta is +33 B minified in signals (holdFrame lane gate +16, observeFlight first-observer hold +17); the brotli deltas are layout over the shifted stream (page base moves +67 B br on +16 B minified). All other caps hold; no cap is loosened beyond measured + 10 B. Size-Exception: fuzzer F7/F12 crash-class fixes — `+ isPending/latest` 9.45 -> 9.47 KB (9,456 B), `page: base` 44.78 -> 44.84 KB (44,829 B), `page: live` 48.45 -> 48.47 KB (48,454 B); +33 B minified in signals, brotli layout. Accepted by the maintainer (2026-10-05). Co-authored-by: Claude via Cursor <[email protected]> --------- Co-authored-by: Claude via Cursor <[email protected]>
…d published-inputs table rows, results in the design doc The 50,000-case generator runs (seeds 3289, 91501, 7, every pair) found two table rows wrong against a rule, fixed in seat.ts (test-only): - L4 / L2 / V1' (D-41): a held node's staged error throws for a leaf or a born-into frame reader; the rows said P. - V3 (F-9, #3305): a verdict reader's plain read of a node staged and in flight with INPUTS_PUBLISHED is the flight's (V4', NR), not the staging. Design doc §4.2 records the differential results (suites, 2k, 50k) and §6 the two rows; RULES-INDEX regenerated for the new #3305 citation. Build output unchanged (size harness: 15/15 bundling scenarios byte-identical). Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]>
…s a CI spec (S0+M1, byte-identical) (#4438) * docs(plans): reader-seat rebuild — build the seat beside the deciders under __TEST__, differential, then swap Co-authored-by: Cursor <[email protected]> * test(signals): reader seat shadow — new seat/slot implementation under __TEST__ beside the existing deciders core/seat.ts computes the reader seat (world/lane/ahead/posture) and the slot table (U/F/L/D/V/Vl/Vp/A/B rows) beside today's deciders; under __TEST__ every read and every recompute compares the two and records disagreements (INV-seat-1..3) into a registry (SEAT_SHADOW_REPORT / __SEAT_SHADOW_STRICT__). Nothing reaches a build: every statement is behind __TEST__ (false in every rollup define); SIGNALS_TEST_DEFINE=true builds a dev dist with it on for the solid/web/generator differential. Design doc §3/§6/§7 updated with the harness as built, the table rows found wrong against a rule (fixed in seat.ts), and the two-readings items the differential leaves open. Co-authored-by: Claude via Cursor <[email protected]> * test(signals): reader seat shadow — 50k differential: staged-error and published-inputs table rows, results in the design doc The 50,000-case generator runs (seeds 3289, 91501, 7, every pair) found two table rows wrong against a rule, fixed in seat.ts (test-only): - L4 / L2 / V1' (D-41): a held node's staged error throws for a leaf or a born-into frame reader; the rows said P. - V3 (F-9, #3305): a verdict reader's plain read of a node staged and in flight with INPUTS_PUBLISHED is the flight's (V4', NR), not the staging. Design doc §4.2 records the differential results (suites, 2k, 50k) and §6 the two rows; RULES-INDEX regenerated for the new #3305 citation. Build output unchanged (size harness: 15/15 bundling scenarios byte-identical). Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]> * docs(plans): reader-seat rebuild §4.2 — three-seed 50k class count, post-fix re-run, plain-build abort indices, untraced residue The 50k row counted seed 3289's classes (133) against the three-seed reads/passes/instances; the aggregate is 220 classes / 8,821 instances before the two 50k table fixes and 209 / 8,706 re-run with the table as committed (the 11 classes the fixes cover go, none appear). The infinite loop abort on each seed is verified against a dist built without SIGNALS_TEST_DEFINE, at the same case index on both builds (7: 1158, 3289: 3963, 91501: 5807). Classes no §6 finding or §7 item names literally (623 instances / 43 classes) are listed and left untraced. Co-authored-by: Claude via Cursor <[email protected]> * docs(plans): reader-seat rebuild §7 — the six two-readings items ruled / chosen 2026-10-28 Co-authored-by: Cursor <[email protected]> * docs(plans): reader-seat rebuild §7 F-vlane — written in D-25; #3884 is the hold's own work, not a persisted posture; swap pins corrected Co-authored-by: Cursor <[email protected]> * test(signals): reader seat S1 M1 — re-baseline the shadow against next @ 5e68925 Table fixes (design doc §6.1): V1'' staged error → E (D-41); the verdict seat is the hold the pass's own node's verdict lane names (vhold); the branch world (creatorsWorld) walks the owner chain of running passes (#4341); ahead only from a lane or verdict seat; verdict reads leave marks and do not raise; Vl4' (latest of a node staged and in flight serves the staging); D8 needs a value (u f is NR); lane rows for a boundary's structure are a derivation's (A15/#4283 — today is right, renderLeaf is EFFECT_RENDER); fallback's read(b._fb) brackets the seat (shadowSeatSave/Restore, #4337); INV-seat-1 amended per D-27 (a leaf that read a born node or the hold's own staging is in the hold's world). shadowKnown allow-list of next bugs the swap fixes by construction, each filed with a generator replay: #4426 (V1' P→C), #4427 (V6 Lv→P), #4428 (B2 born held via the owner-context creator), #4429 (probing leaks into a pulled pass; Vl4 world). §7 F-transitive reopened: today is a third reading; one-level and transitive each differ from it in disjoint born-held shapes. Differential: signals 393 files / solid / web / visibility oracle / generator 2k × {7, 3289, 91501} — zero classes besides the known entries; zero screen differences against next recordings. Build output byte-identical to next (scripts/size: every scenario equal in brotli and minified). Co-authored-by: Claude via Cursor <[email protected]> * docs(plans): reader-seat rebuild §8 — S1 result and decision (2026-10-29): the swap is stopped, S0+M1 land alone as the spec Appends §8 with the measured record from #4430: the four-column size table and the per-module floor breakdown after the levers; the deletions proven, not subsumed and undecidable; the 50k differential inventory with milestone attribution (20 of one D-37 class at M3b, two next bugs closed, two regressions — 3289 #39609 at M3a, 7 #45702 at M3b); the decision (the table replaces the deciders, ≈ −540 B in core.js, but S1 is additive — +294 B brotli on the core floor, +1,061 B on + isPending/latest — because the growth lives in the seam/reveal/hold layer the table does not touch); method lessons (2k is not evidence for a ruling; size is measured before design); what is salvaged and what the next decision is. §5 marked stopped; the brief's §4 is superseded by §8. Co-authored-by: Claude via Cursor <[email protected]> Co-authored-by: Cursor <[email protected]> * docs(reader-seat): correct §8.4 overnight-growth unit (unmangled, not minified) * docs(reader-seat): §8.6 — record the measured salvage results (#4417 adoption, lanes split) * test(signals): give the heap-mark ratio tripwire a 30 s timeout — the __TEST__ shadow puts it past 5 s under coverage --------- Co-authored-by: Cursor <[email protected]> Co-authored-by: Claude via Cursor <[email protected]>
Summary
showcommitted asfalsewithisPending(show) === trueuntil the details can reveal with it, without retroactively holding the already committedvalueupdate.@solidjs/signalspatch changeset. No standalone scratch tests.Reproduction
https://s.olid.uk/id/1xogoHinT9uZhdrpGNy7LQ
The show-line indicator in the playground uses
isPending(value); the DOM regression usesisPending(show). The runtime bug remains independently of that typo:show() ? details() : "hidden"discovers the existing flight only after the reveal write.Verification
JSX_COMPILER=babel: 21 passed.git diff --checkpassed.