fix(signals): held reader disposed / lane direct-commit over a stale hold (#3372, #3377) - #3392
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: 7212a76 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 |
This was referenced Sep 12, 2026
ryansolid
changed the base branch from
fix/async-chain-supersession
to
next
September 12, 2026 23:33
…hold (#3372, #3377) - A transaction whose only reporter is disposed by ambient work was never re-judged: the flush judges only the active transaction and nothing re-enters a parked one. Disposing a pending reader parked in a transaction (`_transition` stamped, STATUS_PENDING) now records it in `wokenTransitions` (the wake introduced with the #3375 boundary-reset ruling); the flush re-enters it from the finally of an idle pass, prunes the dead reporter and commits. - A lane recompute (OPT-dirty) direct-commits `_value` but left a hold staged on an earlier lane-free pass of the same transaction in place; the commit published the older frame over the fresh one. The drop of the superseded hold now applies override or not. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
ryansolid
force-pushed
the
fix/held-restore
branch
from
September 12, 2026 23:35
bc54629 to
7212a76
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #3381 (base:
fix/async-chain-supersession); retarget tonextonce that merges. Cluster 2 of gabbev's 2026-09-11 batch: #3372, #3377.#3372 — a held write lost when its only reader is unmounted
show=trueis written while the<Show>child that readsdetailsis pending, so the write is held with that flight (A15).setMounted(false)then disposes the child — the transaction's only reporter — in an ambient flush. The transaction completes when nothing live reports a flight it waits on, andreporterBlocksSourcealready treats a disposed reporter as dead, but the flush only ever judges the active transaction: a parked one is re-entered by a stamped landing, a stamped recompute or an action resuming, and this disposal is none of those. No check ever ran;show=truestayed staged forever.Fix:
disposeChildren(self)on a node with_transitionandSTATUS_PENDING(a pending reader is always queued as a pending node, so the stamp is reliable) records the transaction inwokenTransitions— the wake introduced with the #3375 ruling in #3381 (a82d2e3). The flush re-enters it from thefinallyof an idle pass, prunes the dead reporter and commits.Pins: the repro; a wake with a surviving outside reader re-parks; a wake adopts no ambient write staged by the pass that disposed the reader (fails without the
!scheduledgate:Other: 1gets dragged into the hold).#3377 —
Pairstuck at0 / 0after an intermediate write restores the initial valuepairreadsdetails()andlatest(count). Thelatest()companion is an optimistic node, so on the pass where the stagedcountdiffers from committed,pairadopts its lane and direct-commits_value(Pair: 2 / 2). On the earlier pass at 2000 — aftersetCount(0)had equality-cancelled the companion's write, so no lane —pairhad stagedPair: 0 / 0as a transaction hold. The direct commit left that hold in the slot; the transaction's commit then published the older frame over the fresh value.Fix: the override branch of the direct-commit path already dropped the superseded hold ("so its queued commit can't clobber the fresh value"); it now does so for any lane recompute, override or not. This widens an override-only rule to lane-adopted nodes including memos — suite green, principle uniform (INV-11 corollary in the internals doc), flagging it for review.
Size
Floor +58 B on top of #3381 (22,915 → 22,973). Scenario caps bumped with notes (brotli deltas +28…+88 B).
Verification
signals 1763/1763 (+1 skipped), solid 595, web 734;
tscclean forsrc/and the new test;size-limitpasses. No existing test expectation changed.Co-authored-by: Claude via Cursor