fix(signals): a derivation's untracked read of a held store value is born held (A29 at the store's untracked paths) - #3520
Closed
ryansolid wants to merge 1 commit into
Conversation
…born held (A29 at the store's untracked paths) Step 4 of DESIGN-CONSOLIDATION move 3b. Core read() serves a staged value to a deriving reader and enters its transaction in the same arm — an untracked read inside a memo is still that memo's read (context persists under untrack), so a mainline memo over a held signal is born held. The store's untracked paths — nodeValue, pendingBackingVisible, readSource's adoption-hold view — restated the value half and dropped the entry: a mainline memo's or user effect's untrack(() => s.n) PUBLISHED the action's unrevealed write. They now call enterStagedRead on the arm that serves the staged value; enterStagedRead takes a null node for a backing (the fold's transaction is passed). The two store tunnels (latest() for store keys, authoritativeServe) keep serving without entering, as before. Discovery: the posture matrix gains memoUntracked / effectUntracked reader kinds (621 -> 851 cells) — the kind that sees S4 and S5, and that shows two more store/signal divergences recorded, not ruled, as S6 (staged-ambient write read by a derivation created inside a foreign action) and S7 (optimistic override with the only reader gated away). Commits docs/DESIGN-CONSOLIDATION.md (dropped from next by c7ec862's squash accident) with a ledger of moves 3a/3b so far; the code citations now point at it. Gate: suite green (+14 pins); oracles identical; the 5-reader subset of the matrix identical to next; +1 B minified core, +130 B minified store; two brotli caps ratcheted. Co-authored-by: Claude via Cursor <noreply@cursor.com>
🦋 Changeset detectedLatest commit: e30fcc7 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 |
ryansolid
added a commit
that referenced
this pull request
Sep 17, 2026
…unobserved (S7; store follows signal) Ruling 2026-09-17: store rules follow signal rules. Of the two divergences the 7-reader posture matrix recorded in #3520, this ships S7 and defers S6. S7 — the slot hook released a property node the moment its last subscriber left, with the optimistic override on it (overrides live on nodes over a clone the setter discards): s.n read 0 while the action was live, where an optimistic signal keeps its override whether or not anything reads it. A node carrying an override or a staged write now defers its release to the flush that resolves it (deferSlotRelease feeds the scheduler's transientStoreNodes sweep — present since the monorepo absorb with exactly these checks, and unfed). +55 B minified store. Pinned: override visible after gating away; node released at settle. S6 — A28 at the backing (a mainline setStore invisible to a derivation created inside a foreign action until the carrying flush) is ruled the same way but DEFERRED: done at the store twin it cost +402 B minified (a node born in the unflushed window must stage the write, and every arm existed twice — core's and the twin's). Pinned at the store's current value with the ruling attached; it closes when the store's value selection shares core's serve (DESIGN-CONSOLIDATION move 3b step 6). Ledger updated. Gate: suite green; oracles identical; matrix: only the S7 cells moved, to the signal's values; solid/web unchanged from next; no size caps exceeded. Co-authored-by: Claude via Cursor <noreply@cursor.com>
ryansolid
added a commit
that referenced
this pull request
Sep 17, 2026
…unobserved (S7; store follows signal) Ruling 2026-09-17: store rules follow signal rules. Of the two divergences the 7-reader posture matrix recorded in #3520, this ships S7 and defers S6. S7 — the slot hook released a property node the moment its last subscriber left, with the optimistic override on it (overrides live on nodes over a clone the setter discards): s.n read 0 while the action was live, where an optimistic signal keeps its override whether or not anything reads it. A node carrying an override or a staged write now defers its release to the flush that resolves it (deferSlotRelease feeds the scheduler's transientStoreNodes sweep — present since the monorepo absorb with exactly these checks, and unfed). +55 B minified store. Pinned: override visible after gating away; node released at settle. S6 — A28 at the backing (a mainline setStore invisible to a derivation created inside a foreign action until the carrying flush) is ruled the same way but DEFERRED: done at the store twin it cost +402 B minified (a node born in the unflushed window must stage the write, and every arm existed twice — core's and the twin's). Pinned at the store's current value with the ruling attached; it closes when the store's value selection shares core's serve (DESIGN-CONSOLIDATION move 3b step 6). Ledger updated. Gate: suite green; oracles identical; matrix: only the S7 cells moved, to the signal's values; solid/web unchanged from next; no size caps exceeded. Co-authored-by: Claude via Cursor <noreply@cursor.com>
Member
Author
|
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 #3517 (← #3516 ← #3515). Step 4 of DESIGN-CONSOLIDATION move 3b. Also commits the design doc.
The bug (S5)
Core
read()serves a staged value to a deriving reader and enters its transaction in the same arm — an untracked read inside a memo is still that memo's read (contextpersists underuntrack), so a mainline memo over a held signal is born held (A29) and publishes nothing until the action commits.The store's untracked paths —
nodeValue,pendingBackingVisible,readSource's adoption-hold view — restated the value half and dropped the entry. A mainline memo's or user effect'suntrack(() => s.n)published the action's unrevealed write to the screen.nextreconcileadoption[1]at creation[]until commit, then[1]Same for
createEffect. Fifteen witness rows, all store shapes now match the signal.The fix
The three store sites call
enterStagedReadon the arm that serves the staged value.enterStagedReadaccepts a null node for a backing (the fold's / adoption's transaction is passed). The two store tunnels (latest()for store keys,authoritativeServefor truth authors) keep serving without entering, unchanged.Discovery: the matrix gets the reader kind that sees this
visibility-oracle-posturegainsmemoUntracked/effectUntracked(an untracked read inside a derivation): 621 → 851 cells. The 5-reader subset is byte-identical tonext; the new rows for the held plain-store state go from1 | 1 | 1(published, no entanglement) to exactly the signal'sHELD | 1≠ ENTANGLED | …. This is the kind that would have caught S4 too.The new rows also show two more store/signal divergences, recorded at their current values, not ruled (S6, S7 in
posture-store-parity, with both sides pinned):0(A28 / fix(signals): oneunflushed— a staging adopted before any flush answers the committed value on every channel (spec O4) #3510), store publishes pending1. Verdict channels already agree (S1); derivation reads don't.x()still reads the override5while the action is live (A17); store'ss.nreads0.Both need a ruling before either side moves.
The design doc
packages/signals/docs/DESIGN-CONSOLIDATION.md— dropped fromnextby c7ec862's squash accident, restored fromdesign/consolidationwith a §0 ledger of moves 3a/3b (what merged, what's in this stack, what each step found, bytes). The code comments in #3515 now cite a file that exists.Gate
nextmemoUntrackedrows for the held store state moved, to the signal's valuesnextorigin/nextMade with Cursor