Skip to content

fix(signals): hold conditional reveals on existing async work - #3305

Merged
ryansolid merged 2 commits into
solidjs:nextfrom
brenelz:fix/conditional-async-reveal-pending
Sep 8, 2026
Merged

ryansolid merged 2 commits into
solidjs:nextfrom
brenelz:fix/conditional-async-reveal-pending

Conversation

@brenelz

@brenelz brenelz commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Hold staged writes when a render reader first observes an unresolved async flight from an earlier flush. This keeps show committed as false with isPending(show) === true until the details can reveal with it, without retroactively holding the already committed value update.
  • Check transition ownership rather than reader initialization: newly created child readers must also hold the reveal, while readers already parked in a transition must not open a second one. Fresh/reset loading boundaries still consume pending and display their fallback.
  • Add coverage to the existing async-semantics and DOM loading suites, plus an @solidjs/signals patch 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 uses isPending(show). The runtime bug remains independently of that typo: show() ? details() : "hidden" discovers the existing flight only after the reveal write.

Verification

  • Signals suite: 1,502 passed, 1 skipped.
  • Solid suite: 585 passed.
  • Web suites: 704 client, 750 server, and 165 hydration tests passed; 2 server tests skipped.
  • DOM loading suite with JSX_COMPILER=babel: 21 passed.
  • Rebuilt runtimes before downstream tests; bundle-size limits, Prettier, and git diff --check passed.

@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 98d457f

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

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

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

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

@codspeed

codspeed Bot commented Sep 7, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 142 untouched benchmarks


Comparing brenelz:fix/conditional-async-reveal-pending (98d457f) with next (6f48a80)1

Open in CodSpeed

Footnotes

  1. No successful run was found on next (98d457f) during the generation of this report, so 6f48a80 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@ryansolid
ryansolid force-pushed the fix/conditional-async-reveal-pending branch from 29cacdb to 6ea30eb Compare September 8, 2026 05:14
…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 <cursoragent@cursor.com>
@ryansolid
ryansolid force-pushed the fix/conditional-async-reveal-pending branch from 6ea30eb to 98d457f Compare September 8, 2026 05:14
@ryansolid

Copy link
Copy Markdown
Member

Ruling: this is a gap, not a semantics change — the same A15 rule (a non-action write whose render surfaces async is held with isPending on the written signal), applied when the reader discovers a flight instead of starting one. Today's fresh-start path opens the transition from handleAsync; nothing did so for a pre-existing, never-held flight, so show committed true while the content froze on "hidden" with nothing reporting pending.

I pushed one commit on top (98d457f8): identical semantics, the new check folded into the existing actualError branch, currentBatch instead of this._batch, and ?? for the error fallback (exact — every caller passes nothing or this node's own _x._error). That takes signals: + createStore from 18 B over the cap on Linux to 14.36 KB, under both the cap and the pre-PR baseline, so no ratchet was needed. I also checked the guards: the _pendingNodes.length gate is what keeps a first mount from opening a reporter-blocked transaction that would stash every effect in the flush, and !node._transition is load-bearing (three createProjection.async isPending tests fail without it). Both stay.

Merging — thanks for the clean reproduction and the boundary-shape tests.

Claude via Cursor

@ryansolid
ryansolid merged commit b6b4804 into solidjs:next Sep 8, 2026
6 checks passed
ryansolid added a commit that referenced this pull request Sep 10, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 10, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 10, 2026
…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 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid added a commit that referenced this pull request Sep 10, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 10, 2026
…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 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
ryansolid added a commit that referenced this pull request Sep 11, 2026
…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 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants