fix(signals): five hold-consistency fixes — re-park sweep, first observer, lane outside view, zombie readers, unchanged-pass trims - #3479
Conversation
🦋 Changeset detectedLatest commit: c66cf6a 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 |
Coverage Report for CI Build 35069760192Coverage remained the same at 71.46%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
|
Merging this PR will regress 1 benchmark
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing |
…et size caps (#3479) `read()`'s override arm now makes one engine call, `GlobalQueue._overrideRead(el, c)`, gated on `CONFIG_HAS_LANE | CONFIG_OVERRIDE_SUPERSEDED` (either implies the engine): the lane outside-view rule (#3460, `readsHeldCommitted`) and the A18 supersession selection (`supersededRead`, #3331) are its two arms, in optimistic.ts. Replaces the separate `_readsHeldCommitted` check and `_supersededRead` slot. -37 B minified in the core floor (24,873 -> 24,836); brotli-neutral. Golf measured against the size-limit harness: terser source for sourceObserved / heldFromStale / the zombie walk compressed WORSE (core floor 9,253 -> 9,301 B brotli) and was dropped. The remaining +100–135 B brotli per entry is the five mechanisms; caps ratcheted with notes: core 9.15 -> 9.35, createStore 16.20 -> 16.45, isPending/latest 11.70 -> 11.90, app floor 11.90 -> 12.05, hydrating 19.40 -> 19.60, hydrating+stores 29.35 -> 29.60, CSR 14.80 -> 15.00, observe 16.40 -> 16.55, observe+attribution 28.00 -> 28.20 KB. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
a140c3e to
3e80a25
Compare
…et size caps (#3479) `read()`'s override arm now makes one engine call, `GlobalQueue._overrideRead(el, c)`, gated on `CONFIG_HAS_LANE | CONFIG_OVERRIDE_SUPERSEDED` (either implies the engine): the lane outside-view rule (#3460, `readsHeldCommitted`) and the A18 supersession selection (`supersededRead`, #3331) are its two arms, in optimistic.ts. Replaces the separate `_readsHeldCommitted` check and `_supersededRead` slot. -37 B minified in the core floor (24,873 -> 24,836); brotli-neutral. Golf measured against the size-limit harness: terser source for sourceObserved / heldFromStale / the zombie walk compressed WORSE (core floor 9,253 -> 9,301 B brotli) and was dropped. The remaining +100–135 B brotli per entry is the five mechanisms; caps ratcheted with notes: core 9.15 -> 9.35, createStore 16.20 -> 16.45, isPending/latest 11.70 -> 11.90, app floor 11.90 -> 12.05, hydrating 19.40 -> 19.60, hydrating+stores 29.35 -> 29.60, CSR 14.80 -> 15.00, observe 16.40 -> 16.55, observe+attribution 28.00 -> 28.20 KB. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…3479 review) A lane pass on a memo publishes its speculative result into the override slot (`laneOverride`, CONFIG_DERIVED_OVERRIDE) instead of direct-committing `_value`, so the committed view a reader off the lane is served (#3460) is a whole frame: the held source and its derivations together, never a committed shadow beside a speculative memo (gabbev's fuzzer, latest cohort: 57 -> 5 published-derivation disagreements, torn tuples to an effect 26 -> 0). - Off the lane is provenance, not membership: a pass under the lane's own transaction (its async's landing re-entering it) is the lane's work — the `1:0` frame of an optimistic value that never finished preparing. - The revert PROMOTES a derived override the truth confirmed instead of re-deriving (no re-ask waterfall after the reveal); a superseded one drops. - A derived override is a plain member: merges lanes through itself, does not stop pending propagation, suspends its lane readers on its re-ask, is skipped by body-end supersession and the authoritative-blockage census, carries no `_overrideTime` or provenance stamp, is no acknowledgement to the hold census. - Every pass over a live lane member carrying a derived override is the lane's pass, whatever channel dirtied it (a boundary reset re-running a lane-born memo read its re-derived lane view as a differing truth and demoted the lane; fuzzer latest-1 #2481). A fresh lane publish clears a supersession in force. Pins in tests/lane-outside-view.test.ts; A17 and INV-11 amended; size caps ratcheted (isPending/latest 11.90 -> 12.05, store app 29.60 -> 29.75, hydrating 19.60 -> 19.70 KB). Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
…3479 review) A lane pass on a memo publishes its speculative result into the override slot (`laneOverride`, CONFIG_DERIVED_OVERRIDE) instead of direct-committing `_value`, so the committed view a reader off the lane is served (#3460) is a whole frame: the held source and its derivations together, never a committed shadow beside a speculative memo (gabbev's fuzzer, latest cohort: 57 -> 5 published-derivation disagreements, torn tuples to an effect 26 -> 0). - Off the lane is provenance, not membership: a pass under the lane's own transaction (its async's landing re-entering it) is the lane's work — the `1:0` frame of an optimistic value that never finished preparing. - The revert PROMOTES a derived override the truth confirmed instead of re-deriving (no re-ask waterfall after the reveal); a superseded one drops. - A derived override is a plain member: merges lanes through itself, does not stop pending propagation, suspends its lane readers on its re-ask, is skipped by body-end supersession and the authoritative-blockage census, carries no `_overrideTime` or provenance stamp, is no acknowledgement to the hold census. - Every pass over a live lane member carrying a derived override is the lane's pass, whatever channel dirtied it (a boundary reset re-running a lane-born memo read its re-derived lane view as a differing truth and demoted the lane; fuzzer latest-1 #2481). A fresh lane publish clears a supersession in force. Pins in tests/lane-outside-view.test.ts; A17 and INV-11 amended; size caps ratcheted (isPending/latest 11.90 -> 12.05, store app 29.60 -> 29.75, hydrating 19.60 -> 19.70 KB). Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
3e80a25 to
bc3571b
Compare
…rver, lane outside view, zombie readers, unchanged-pass trims (#3456 #3458 #3460 #3463 #3469) Batch 2 of GabbeV's hold-consistency reports, audited against `next` after base commit. pass carried: `recompute`'s catch settles, against the node, every previously carried source absent from the new set (the re-park twin of the unchanged-value recovery sweep). A conditional whose async branch was cancelled no longer waits forever on a flight it has no path to. has an entry (#3374); when it has none the reader is the flight's first observer, and the pending status is notified up the reader's queue chain under the transaction (INV-3, the one registration site). The transaction now waits on the flight it revealed a reader of. transition from the outside… we wouldn't hold a sync write on a transition. Lanes are the same"). `readsHeldCommitted` (lanes.ts): a render effect OFF a held lane reading an override or a `latest()` shadow is served the committed value, publishes now, entangles nothing, and is queued on the lane's render queue for a re-run at the release. Hooked from `read()`'s override arm (`GlobalQueue._readsHeldCommitted`, `CONFIG_HAS_LANE`-gated) and `latestRead`, replacing the another-lane-only branch. `latest()` is not a special case. reporter is live for every hold until the commit that disposes it; walk its owner chain to the transaction staging its removal, and count it moot only when that transaction is the one being judged (or is done). `sourceObserved` keeps a zombie the verdict passed over rather than pruning it. know at its tail whether the flush will park. `heldTrims` defers the trim to the flush's verdict: drained by `commitPendingNodes`, cleared on a park. Creation, OPT-dirty and tracked-effect passes trim at once as before. Docs: A15 (lanes corollary, first observer, zombie readers), A17 (every render effect off the lane sees the committed view), A30 (#3469 paragraph); INTERNALS §2/§3 bullets; RULES-INDEX regenerated. Core floor: 24,478 → 24,873 (+395, conscious bump to 25,000, all five seams core-retained). Pinned: tests/pending-source-repark, tests/first-observer-stale-reader, tests/lane-outside-view, tests/held-frame-dependencies. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…et size caps (#3479) `read()`'s override arm now makes one engine call, `GlobalQueue._overrideRead(el, c)`, gated on `CONFIG_HAS_LANE | CONFIG_OVERRIDE_SUPERSEDED` (either implies the engine): the lane outside-view rule (#3460, `readsHeldCommitted`) and the A18 supersession selection (`supersededRead`, #3331) are its two arms, in optimistic.ts. Replaces the separate `_readsHeldCommitted` check and `_supersededRead` slot. -37 B minified in the core floor (24,873 -> 24,836); brotli-neutral. Golf measured against the size-limit harness: terser source for sourceObserved / heldFromStale / the zombie walk compressed WORSE (core floor 9,253 -> 9,301 B brotli) and was dropped. The remaining +100–135 B brotli per entry is the five mechanisms; caps ratcheted with notes: core 9.15 -> 9.35, createStore 16.20 -> 16.45, isPending/latest 11.70 -> 11.90, app floor 11.90 -> 12.05, hydrating 19.40 -> 19.60, hydrating+stores 29.35 -> 29.60, CSR 14.80 -> 15.00, observe 16.40 -> 16.55, observe+attribution 28.00 -> 28.20 KB. Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
…3479 review) A lane pass on a memo publishes its speculative result into the override slot (`laneOverride`, CONFIG_DERIVED_OVERRIDE) instead of direct-committing `_value`, so the committed view a reader off the lane is served (#3460) is a whole frame: the held source and its derivations together, never a committed shadow beside a speculative memo (gabbev's fuzzer, latest cohort: 57 -> 5 published-derivation disagreements, torn tuples to an effect 26 -> 0). - Off the lane is provenance, not membership: a pass under the lane's own transaction (its async's landing re-entering it) is the lane's work — the `1:0` frame of an optimistic value that never finished preparing. - The revert PROMOTES a derived override the truth confirmed instead of re-deriving (no re-ask waterfall after the reveal); a superseded one drops. - A derived override is a plain member: merges lanes through itself, does not stop pending propagation, suspends its lane readers on its re-ask, is skipped by body-end supersession and the authoritative-blockage census, carries no `_overrideTime` or provenance stamp, is no acknowledgement to the hold census. - Every pass over a live lane member carrying a derived override is the lane's pass, whatever channel dirtied it (a boundary reset re-running a lane-born memo read its re-derived lane view as a differing truth and demoted the lane; fuzzer latest-1 #2481). A fresh lane publish clears a supersession in force. Pins in tests/lane-outside-view.test.ts; A17 and INV-11 amended; size caps ratcheted (isPending/latest 11.90 -> 12.05, store app 29.60 -> 29.75, hydrating 19.60 -> 19.70 KB). Co-authored-by: Claude via Cursor <noreply@cursor.com> Co-authored-by: Cursor <cursoragent@cursor.com>
bc3571b to
c66cf6a
Compare
Batch 2 of @GabbeV's hold-consistency reports, audited against
nextafter #3473. Each reproduced at the core level and pinned; every issue pin fails on the base commit (verified), the twin pins (existing behavior) pass on both.Closes #3456, closes #3458, closes #3460, closes #3463, closes #3469.
Ruling applied (#3460)
Maintainer: "a held lane is basically a micro transition from the outside… we wouldn't hold a sync write on a transition. Lanes are the same." A render effect off a held lane is a stale reader of it: it sees the committed value (which is what is on screen — the lane defers its own readers' runs), publishes now, entangles nothing, and re-runs at the release.
latest()is not special — same rule for acreateOptimisticsource. Inside, a reader on the lane sees the lane's values and the parent transaction's landings as before.Fixes
recompute's catch settles every source the earlier pass carried that the re-parked set no longer contains (the re-park twin of the unchanged-value recovery sweep)heldFromStale: when the transaction has no entry for the flight, the reader (its first observer) notifies the pending status up its queue chain under the transaction — INV-3, the one registration sitelatestreaders disagreereadsHeldCommitted(lanes.ts) fromread()'s override arm (CONFIG_HAS_LANE-gated hook) andlatestRead; the release re-run rides the lane's own render queuelatestwhile its reader is visiblereporterBlocksSource(reporter, source, verdict): a zombie is live until the commit that disposes it; moot only for the verdict of the transaction staging its removal.sourceObservedkeeps a zombie the verdict passed overheldTrims: an unchanged pass's dep trim waits on the flush's verdict (drained at commit, dropped on park); creation / OPT-dirty / tracked-effect passes trim at onceSemantics check
A: 2reveals withB: 1) — the memo is served the stagedband enters the hold (A29). This is the pre-existingsum = a() + b()behavior onnext, not a new shift; the report accepts either outcome. The render-effect arm follows its inputs at once (Selected: 2on the write,1at the commit).Docs
A15 (lanes corollary extended; first observer; zombie readers), A17 (every render effect off the lane sees the committed view), A30 (#3469 paragraph); INTERNALS §2/§3 bullets; RULES-INDEX regenerated.
Size
Core floor 24,478 → 24,873 (+395; ceiling bumped to 25,000 with the seams listed in
treeshake.test.ts). All five are core-retained; the #3460 rule itself lives inlanes.tsand sheds with the engine. One golf pass applied (verdictpassed through as the transaction, no ternaries).Tests
signals 190/190 files, solid 28/28, web 93/93 against the rebuilt
dist/.New pins:
tests/pending-source-repark.test.ts,tests/first-observer-stale-reader.test.ts,tests/lane-outside-view.test.ts,tests/held-frame-dependencies.test.ts.Review follow-up: lanes stage (third commit)
@GabbeV's differential fuzzing on the first commit found
1:0— an optimistic value that never finished preparing revealed beside its old derivation — and, once that was fixed, a torn-tuple class in thelatestcohort: an outsider mounted mid-hold saw the source's committed0beside a derivation's speculative1. The #3460 rule needs the committed view to be a whole frame, and the lane mechanism couldn't serve one because lane members direct-committed their speculative results into_value(INV-11's "lane direct commit").Ruling: an optimistic derivation is an override. A lane pass on a memo now publishes into the override slot as a derived override (
laneOverride,CONFIG_DERIVED_OVERRIDE);_valuestays committed. The lane's own readers and direct reads see the optimistic frame, a reader off the lane sees the committed one, neither torn. The revert promotes a derived override the truth confirmed (no re-ask waterfall after the reveal) and drops one it superseded. A derived override is a plain member everywhere a written override means intent (merging, pending propagation, body-end supersession, the authoritative-blockage census, the hold census).Two corollaries the fuzzer forced: off the lane is provenance, not membership (a pass under the lane's own transaction — its async's landing re-entering it — is the lane's work), and every pass over a live lane member carrying a derived override is the lane's pass whatever channel dirtied it (a boundary reset re-ran a lane-born memo plainly; A18's sync twin took its re-derived lane view for a differing truth and demoted the lane —
latest-1 #2481, the boundary publishedundefined).Fuzzer (8 cohorts × 2 seeds × 5000, this tree vs
next):latestS1 published-derivation disagreements 57→5 / 52→6, torn tuples to an effect 26→0;branchesS1 13→2 / 16→2, required-reader L1 6→0 / 10→2; everything else flat. Six new O1 findings inlatestare the fuzzer's model disagreeing with the #3460 ruling (a ready optimistic source not publishing to an outsider while the action is open) — that is the rule, not a regression.Size: isPending/latest 11.90→12.05 KB, store app 29.60→29.75, hydrating 19.60→19.70 (brotli scattered a ~40 B branch ±50 B across scenarios). A17 and INV-11 amended; two new pins in
lane-outside-view.test.ts, plus the #2481 one.