Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/reconcile-unchanged-presence-no-hold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@solidjs/signals": patch
---

A store fold's presence notification (`in` subscribers) now diffs the old and new presence of each observed key before writing the node, as the value notification already does (#3743). `setSignal` joins a held node's transaction before its equality gate (A34 (1): a write to a held node is a proposal, the same value or another), so a `reconcile()` outside an action that had deleted an observed key — the incoming snapshot leaving it absent too — made the whole tick the action's: an unrelated `a.value` stayed stale until the action settled. A real presence change still notifies and still proposes on a held node.

The adoption's diff base now materializes a nested prototype-overlay draft (a wide owned record) before it is taken: through the overlay's prototype a key the draft had deleted still read as present, so the presence skip fired on a real deletion and a reconcile restoring the key never re-proposed on the held leaf (it committed the draft's `undefined` beside a backing that had the key).

Two optimistic-store fixes the diff uncovered: a container carrying an arrangement guess is now told of an arrangement change whether or not anything subscribes to the container (for a guessed container the write is the landing that judges the guess — before, only the unconditional presence write reached the lane, so a newer question's rows landing beneath an optimistic push published beside it when the reader subscribed to leaves only); and an older truth re-based under an arrangement guess no longer re-stages a slot whose row the committed backing already shows by key, nor an unchanged `length` (a spurious frame for leaf-only readers).
6 changes: 3 additions & 3 deletions packages/signals/docs/RULES-INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul
| A15 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:221` | async.ts×2 constants.ts×1 core.ts×3 lanes.ts×4 scheduler.ts×13 verdict.ts×2 | async-chain-supersession.test.ts×1 first-observer-stale-reader.test.ts×1 held-restore.test.ts×1 l2-contract.test.ts×7 lane-contract.test.ts×1 lane-hold-on-observation.test.ts×1 lane-outside-view.test.ts×1 lane-pass-stamped-effect-3662.test.ts×1 mount-over-foreign-hold-3761.test.ts×2 overlapping-flights.test.ts×3 posture-born-held-and-observation.test.ts×4 posture-store-parity.test.ts×2 reveal-carve-out.test.ts×2 shared-effect-no-entangle.test.ts×1 spec-async-semantics.test.ts×2 stale-read-uninitialized-cross-transition.test.ts×1 superseded-source-blocks-3462.test.ts×2 tick-scoped-pass-transaction.test.ts×1 treeshake.test.ts×4 visibility-oracle-store.states.ts×6 visibility-oracle.states.ts×7 visibility-oracle.test.ts×1 write-proposals-3494.test.ts×1 | [ruled, amended in place 2026-07-06 (promoted from B3)] Transition entanglement is graph-driven; lanes settle as one reveal — (was B3) Transition entanglement is graph-driven: writes whose async work … |
| A16 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:193` | scheduler.ts×1 | spec-async-semantics.test.ts×1 strict-read-pending-store.test.ts×2 uninitialized-visibility.test.ts×1 visibility-oracle-store.states.ts×2 visibility-oracle.states.ts×2 visibility-oracle.test.ts×1 | [ruled, amended in place 2026-07-06 (promoted from B5)] `isPending` never throws in untracked contexts — (was B5) `isPending` never throws in untracked contexts — thunks that throw real errors or read… |
| A17 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:51` | async.ts×3 constants.ts×1 lanes.ts×5 scheduler.ts×2 verdict.ts×1 map.ts×1 store.ts×3 | lane-uninitialized-landing-3648.test.ts×5 optimistic-read-lane-not-transaction-3698.test.ts×2 optimistic-undefined-override.test.ts×1 posture-store-parity.test.ts×1 refresh-await.test.ts×1 reveal-gating-contract.test.ts×3 spec-async-semantics.test.ts×10 createOptimisticStore.test.ts×2 kanban-a17-fixture.test.ts×3 optimistic-list-mutation-matrix.test.ts×1 optimistic-maparray-index-frame-f1.test.ts×1 optimistic-untracked-reads-f3-f5.test.ts×1 signal-store-twins-qd.test.ts×1 treeshake.test.ts×1 until.test.ts×1 visibility-oracle-store.states.ts×24 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×20 visibility-oracle.test.ts×1 | [ruled, amended in place 2026-07-06 (promoted from C4)] An active override is the displayed value until its transaction commits, and the graph's value until its own source answers — **Statement (curre… |
| A18 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:61` | action.ts×1 async.ts×2 core.ts×3 lanes.ts×8 scheduler.ts×2 types.ts×1 verdict.ts×1 map.ts×1 optimistic.ts×1 projection.ts×1 | body-end-supersession-visibility.test.ts×4 createOptimistic.test.ts×3 lane-contract.test.ts×1 lane-frame-deferred-run-3662.test.ts×1 lane-outside-view.test.ts×1 lane-uninitialized-landing-3648.test.ts×5 optimistic-move-duplicate-3548.test.ts×2 optimistic-read-lane-not-transaction-3698.test.ts×4 posture-store-parity.test.ts×5 spec-async-semantics.test.ts×3 flight-owned-transaction.test.ts×1 optimistic-list-mutation-matrix.test.ts×1 optimistic-untracked-reads-f3-f5.test.ts×1 signal-store-twins-qd.test.ts×1 superseded-before-first-commit.test.ts×4 visibility-oracle-store.states.ts×8 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×19 visibility-oracle.test.ts×1 | [ruled, amended in place 2026-07-07 (promoted from B4)] An override lives exactly as long as its own transaction; a newer truth from the source supersedes it in the graph immediately, on screen at com… |
| A18 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:61` | action.ts×1 async.ts×2 core.ts×3 lanes.ts×8 scheduler.ts×2 types.ts×1 verdict.ts×1 map.ts×1 optimistic.ts×1 projection.ts×1 | body-end-supersession-visibility.test.ts×4 createOptimistic.test.ts×3 lane-contract.test.ts×1 lane-frame-deferred-run-3662.test.ts×1 lane-outside-view.test.ts×1 lane-uninitialized-landing-3648.test.ts×5 optimistic-move-duplicate-3548.test.ts×2 optimistic-read-lane-not-transaction-3698.test.ts×4 posture-store-parity.test.ts×5 spec-async-semantics.test.ts×3 flight-owned-transaction.test.ts×1 optimistic-list-mutation-matrix.test.ts×1 optimistic-untracked-reads-f3-f5.test.ts×1 signal-store-twins-qd.test.ts×1 unchanged-presence-no-hold-3743.test.ts×2 superseded-before-first-commit.test.ts×4 visibility-oracle-store.states.ts×8 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×19 visibility-oracle.test.ts×1 | [ruled, amended in place 2026-07-07 (promoted from B4)] An override lives exactly as long as its own transaction; a newer truth from the source supersedes it in the graph immediately, on screen at com… |
| A19 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:121` | constants.ts×1 core.ts×6 scheduler.ts×2 types.ts×1 verdict.ts×4 store.ts×1 | lane-uninitialized-landing-3648.test.ts×2 mount-over-foreign-hold-3761.test.ts×2 spec-async-semantics.test.ts×3 derived-presence-async-3726.test.ts×2 superseded-before-first-commit.test.ts×3 uninitialized-visibility.test.ts×1 visibility-oracle-store.states.ts×8 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×14 visibility-oracle.test.ts×1 write-proposals-3494.test.ts×1 | [ruled, amended in place 2026-07-07 (promoted from C1)] `isPending(x)` ≡ the observable value is not final (three causes) — (was C1 — **partially reverses an earlier decision**) **Definition: `isPendi… |
| A20 | superseded | `docs/SPEC-ASYNC-SEMANTICS.md:380` | — | question-scoped-pending.test.ts×2 spec-async-semantics.test.ts×3 createOptimisticStore.test.ts×1 | [superseded 2026-07-13 by A24] (superseded) Optimistic writes announce a store-wide pending — (**SUPERSEDED 2026-07-13 by A24** — the mask is deleted; optimistic writes are verdict-inert. Kept for the… |
| A21 | superseded | `docs/SPEC-ASYNC-SEMANTICS.md:387` | — | question-scoped-pending.test.ts×3 spec-async-semantics.test.ts×3 | [superseded 2026-07-13 by A24] (superseded) The store-wide mask — (**SUPERSEDED 2026-07-13 by A24** — the store-wide mask is deleted with the mask model; nothing silences a new question. The effective… |
Expand All @@ -78,7 +78,7 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul
| A31 | live | `docs/SPEC-ASYNC-SEMANTICS.md:103` | boundaries.ts×1 core.ts×1 verdict.ts×1 | ispending-combined-atomic-3442.test.ts×1 | [live 2026-09-14 (#3442)] A memo computes under its own lane posture, never its puller's — A memo's value is one shared slot every reader sees, so its pass runs under the lane posture the memo itself … |
| A32 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:111` | core.ts×4 lanes.ts×1 store.ts×1 | visibility-oracle-store.states.ts×8 visibility-oracle-store.test.ts×1 visibility-oracle.states.ts×9 visibility-oracle.test.ts×1 | [ruled 2026-09-14] Children-forbidden readers see the frame, not the graph — `createTrackedEffect` and `onSettled` callbacks are effect-phase code that runs after the frame is decided. They read the f… |
| A33 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:245` | boundaries.ts×1 scheduler.ts×1 | async-chain-supersession.test.ts×2 boundary-not-born-held-3540.test.ts×2 ispending-in-boundary-on-3528.test.ts×2 loading-reset-collects-forwarded-3459.test.ts×3 | [ruled 2026-09-12 (#3375)] A fallback-caught flight holds no transaction; a Loading reset moves the hold onto the boundary — A `<Loading>` boundary showing its fallback is the display of everything un… |
| A34 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:255` | constants.ts×1 core.ts×6 lanes.ts×2 scheduler.ts×2 store.ts×3 | a34-writes-then-derivations.test.ts×2 createMemo.test.ts×1 derived-write-then-derivation-3733.test.ts×1 finalize-reentry.test.ts×2 held-derivation-not-a-proposal-3612.test.ts×6 optimistic-list-mutation-matrix.test.ts×1 woken-transaction-adopts-staged-bump.test.ts×1 transition-corpse-revival.test.ts×1 treeshake.test.ts×2 visibility-oracle.states.ts×2 write-proposals-3494.test.ts×5 | [ruled 2026-09-16 (#3494)] A write is a proposal: one on a held node entangles its tick; one that nets to the committed value is none — A write proposes a value for a node. **Held, both are suggestion… |
| A34 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:255` | constants.ts×1 core.ts×6 lanes.ts×2 scheduler.ts×2 store.ts×4 | a34-writes-then-derivations.test.ts×2 createMemo.test.ts×1 derived-write-then-derivation-3733.test.ts×1 finalize-reentry.test.ts×2 held-derivation-not-a-proposal-3612.test.ts×6 optimistic-list-mutation-matrix.test.ts×1 unchanged-presence-no-hold-3743.test.ts×3 woken-transaction-adopts-staged-bump.test.ts×1 transition-corpse-revival.test.ts×1 treeshake.test.ts×2 visibility-oracle.states.ts×2 write-proposals-3494.test.ts×5 | [ruled 2026-09-16 (#3494)] A write is a proposal: one on a held node entangles its tick; one that nets to the committed value is none — A write proposes a value for a node. **Held, both are suggestion… |
## V — fixed violations

| id | status | defined | cited in src | cited in tests | statement (at definition) |
Expand Down Expand Up @@ -390,7 +390,7 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul
| §6c | live | `docs/INTERNALS-STORE-STATE.md:334` | — | createProjection.async.test.ts×1 flight-owned-transaction.test.ts×1 | Store-wide status gating (RUL-7) |
| §6d | live | `docs/INTERNALS-STORE-STATE.md:347` | reconcile.ts×2 target.ts×2 | — | Diff reachability (RUL-11) |
| §7 | live | `docs/INTERNALS-STORE-STATE.md:359` | optimistic.ts×1 projection.ts×1 | — | Projections & optimism layering |
| §7b | live | `docs/INTERNALS-STORE-STATE.md:369` | scheduler.ts×1 affects.ts×1 optimistic.ts×2 projection.ts×1 reconcile.ts×1 store.ts×6 target.ts×4 | optimistic-chained-revert-3672-memo.test.ts×1 | Chained backing (cross-store) — spec |
| §7b | live | `docs/INTERNALS-STORE-STATE.md:369` | scheduler.ts×1 affects.ts×1 optimistic.ts×2 projection.ts×1 reconcile.ts×1 store.ts×7 target.ts×4 | optimistic-chained-revert-3672-memo.test.ts×1 | Chained backing (cross-store) — spec |
| §8 | live | `docs/INTERNALS-STORE-STATE.md:440` | — | l2-contract.test.ts×1 reconcile-resend-identity.test.ts×1 | Assumptions / open questions |
| §8b | live | `docs/INTERNALS-STORE-STATE.md:496` | — | — | Suite-mined rules (2026-08-16) — index & rulings needed |
| §9 | live | `docs/INTERNALS-STORE-STATE.md:732` | — | — | Decision log |
Expand Down
Loading
Loading