diff --git a/.changeset/create-deferred.md b/.changeset/create-deferred.md
new file mode 100644
index 0000000000..0bb39eff81
--- /dev/null
+++ b/.changeset/create-deferred.md
@@ -0,0 +1,8 @@
+---
+"@solidjs/signals": patch
+"solid-js": patch
+---
+
+`createDeferred(fn, options?)`: an async memo that may lag, but never leads. Before its first answer it is an ordinary async memo (readers suspend to ``, or `loadingValue` shows). After it, a refetch holds nothing: readers keep the previous answer until the new one lands, the rest of the screen moves on, and `isPending` reports the refetch on the node and on everything derived from it, store keys included. A refetch that read a held value lands with that hold. A rejection errors like any memo. `refresh(d)` is a quiet re-ask, and `await refresh(d)` and `until` wait for the landing. It is `createMemo` on the server and hydrates like one.
+
+The rules: F-1 and F-2 are amended for declared lag, and D-40 / S-41 are new. The `affects()` mark core moved to its own module (`affects-marks.ts`), which `createDeferred` shares. A mark on the source of a derived store now covers that store's keys.
diff --git a/documentation/solid-2.0/MIGRATION.md b/documentation/solid-2.0/MIGRATION.md
index 3015f4d15f..af0b280069 100644
--- a/documentation/solid-2.0/MIGRATION.md
+++ b/documentation/solid-2.0/MIGRATION.md
@@ -1062,7 +1062,7 @@ If you need a standard Observable/AsyncIterable interface for external consumers
- **`produce`** → now the default store setter behavior (draft-first)
- **`createMutable` / `modifyMutable`** → use `createStore` with draft setters
- **`from` / `observable`** → async iterators
-- **`createDeferred`** → removed; handle outside Solid
+- **`createDeferred`** → same name, new meaning: an async memo that may lag but never leads (keeps its last answer while a refetch is in flight; `isPending` reports the refetch). 1.x's idle-time deferral and `timeoutMs` are gone; with a synchronous function it behaves like `createMemo`
- **`indexArray`** → use `mapArray` with `keyed: false`
- **`resetErrorBoundaries`** → no longer needed (error boundaries heal automatically)
- **`enableScheduling`** → removed
diff --git a/packages/signals/docs/RULES-DERIVED.md b/packages/signals/docs/RULES-DERIVED.md
index fccdb42cd4..da1e5d7a79 100644
--- a/packages/signals/docs/RULES-DERIVED.md
+++ b/packages/signals/docs/RULES-DERIVED.md
@@ -334,6 +334,27 @@ An `` flipping to its fallback is a boundary going back to its fallback
---
+## F. Declared lag (F-1, F-2, F-7, F-9)
+
+### D-40. A deferred source lags its readers and never leads them
+
+**From:** F-1, F-2 (both amended 2026-10-14 for declared lag), F-7, F-9, F-4, F-12. **Scenarios:** S-41.
+
+`createDeferred(fn)` is an async memo whose author declared that its previous answer is acceptable while the next one loads. Its first load is a first load like any: a reader suspends to a boundary or holds (F-2, F-4), and with `loadingValue` the declared first paint shows instead, verdict-quiet (D-30). After its first answer:
+
+- **Nothing waits for it.** A change that re-asks it holds nothing on its account: its readers keep the answer they show, and the rest of the change shows now. An unready source it reads (`createDeferred(() => query())`) is the same: the node keeps its answer, nothing pends through it.
+- **Its landing is a change of its own.** It shows when it lands, unless it lands into a hold (next bullet); an unrelated hold does not keep it back.
+- **It never leads.** A re-ask that read a held value derived from that hold's world, so its answer lands into that hold and shows with its commit (F-7). Its readers that also read a held value see the committed one, as any reader does.
+- **A held answer stays held.** Once a hold has taken its landing (a reader downstream is pending and staged it), a change that re-asks it still holds nothing: the change shows now, and the hold keeps the landing it took and shows it at its commit.
+- **The verdict sees it.** `isPending` of the node, and of everything derived from it (a memo over it, a derived store's keys), is `true` from the re-ask until the landing (F-9: a new question). A `refresh()` re-ask is quiet. The verdict and the landed value change in one frame.
+- **Truth readers wait for it.** `await refresh(d)` delivers the landing; `until`'s predicate does not see the stale answer of a source it derives from (the reader's own declaration: `resolve` takes the first settled value and does not wait).
+- **Errors are not lag.** A rejected re-ask errors like any memo (F-12); the stale answer never masks it.
+- **On the server it is `createMemo`** (everything is first load there).
+
+**Collapses:** `docs/create-deferred.md` D1–D11 (2026-09-08, D11 ruled 2026-10-04; its lane-landing mechanism is superseded, see its §6). **Status:** standing, built 2026-10-14 (`tests/create-deferred.test.ts`, `tests/create-deferred-3710.test.ts`).
+
+---
+
## Flagged — rulings that cannot cite a fundamental, stale archive text, mistakes
| item | finding | disposition |
diff --git a/packages/signals/docs/RULES-FUNDAMENTALS.md b/packages/signals/docs/RULES-FUNDAMENTALS.md
index 8bc32d74ef..2226570e67 100644
--- a/packages/signals/docs/RULES-FUNDAMENTALS.md
+++ b/packages/signals/docs/RULES-FUNDAMENTALS.md
@@ -32,6 +32,7 @@ These are the only words the fundamentals use. Internal names (transaction, stag
- **First load.** The wait before a source has its first answer. A first load is _loading_, not a change: there is no previous content to keep. A memo created during a hold that reads the held change (_born held_, D-2) is loading in the same sense: it has no value the screen can show until that hold commits. A read of something loading suspends — to a boundary, or into the hold (F-2, F-4) — and `isPending` of it gives no verdict, because there is nothing shown to be stale (F-9).
- **Question / re-ask.** A source's inputs are its question. An input changing asks a new question; `refresh()`, polling, an action's confirming refetch re-ask the same one.
- **Display-ahead reader.** `latest(x)`, `isPending(x)`, an optimistic value: a reader that shows a held change (or the verdict about it) before the hold reveals it.
+- **Declared lag.** `createDeferred(fn)`: a source whose author has declared that its previous answer is an acceptable answer while the next one loads. After its first answer, its own re-asks hold nothing and its readers keep the answer they show until the new one lands (D-40). It is the counterpart of a display-ahead reader: that one shows a held change early, this one shows a change's consequence late, and neither is a hold.
- **Lane.** The world a display-ahead read opens: the screen plus what it shows ahead. What is rendered from a display-ahead read lives in its lane, and the lane holds _itself_ on its own async — a hold of its own, separate from the hold it reads ahead of (F-6).
- **Flush.** The unit of visibility. Writes become visible at the flush that carries them; a manual `flush()` ends a tick.
@@ -39,19 +40,19 @@ These are the only words the fundamentals use. Internal names (transaction, stag
## F-1. The screen is whole
-**Immutable.** Every frame the screen shows is consistent: a value and everything on screen derived from it changed in the same frame. The screen never shows a new value beside a stale derivation of it, and never a derivation ahead of its input. This holds for every kind of on-screen reader — a plain binding, a memo between, a boundary's content, a `latest()` view and what is rendered from it — and in every world the screen can show: the committed one, a held one, an optimistic one.
+**Immutable.** Every frame the screen shows is consistent: a value and everything on screen derived from it changed in the same frame. The screen never shows a new value beside a stale derivation of it, and never a derivation ahead of its input. This holds for every kind of on-screen reader — a plain binding, a memo between, a boundary's content, a `latest()` view and what is rendered from it — and in every world the screen can show: the committed one, a held one, an optimistic one. The one exception is the author's declaration of lag (amended 2026-10-14): a `createDeferred` node keeps showing its previous answer beside the change that re-asked it, and so does what is rendered from it, until its own answer lands. It may lag the screen; it never leads it (F-7, D-40).
-**What it does not say.** It does not say that two _unrelated_ changes must land together (F-2 decides what waits for what). It does not say that imperative, untracked reads are part of a frame — they read the screen as it stands (D-29, D-34). It does not say control and content must agree when the content is _absent_ by the author's choice (a fallback is content: F-4).
+**What it does not say.** It does not say that two _unrelated_ changes must land together (F-2 decides what waits for what). It does not say that imperative, untracked reads are part of a frame — they read the screen as it stands (D-29, D-34). It does not say control and content must agree when the content is _absent_ by the author's choice (a fallback is content: F-4). It does not say content the author declared may lag agrees with the control that re-asked it (D-40).
-**Collapses:** A10 (`[isPending(x), x()]` atomic), A15's no-tearing core, A17's "no-tearing is an effect-level concern", A29/#3408 (`Panel: 1` beside `Count: 0` was the violation), #3479 "the frame is whole", #3851 (`content 1` beside `x = 0`), fuzzer finding F6 (#3811, the disarmed half — a lane revealing ahead of content a disarmed boundary is still showing), OL-R26, OS-R9, #3761 (ruled against), N1 (reverted). **Derived:** D-1–D-3, D-9, D-10, D-25–D-28, D-34. **Scenarios:** S-2–S-4, S-11, S-30, S-31, S-39.
+**Collapses:** A10 (`[isPending(x), x()]` atomic), A15's no-tearing core, A17's "no-tearing is an effect-level concern", A29/#3408 (`Panel: 1` beside `Count: 0` was the violation), #3479 "the frame is whole", #3851 (`content 1` beside `x = 0`), fuzzer finding F6 (#3811, the disarmed half — a lane revealing ahead of content a disarmed boundary is still showing), OL-R26, OS-R9, #3761 (ruled against), N1 (reverted). **Derived:** D-1–D-3, D-9, D-10, D-25–D-28, D-34, D-40. **Scenarios:** S-2–S-4, S-11, S-30, S-31, S-39, S-41.
## F-2. A change that needs async to be shown is held; the screen keeps what it showed
-**Immutable.** When showing a change would put a render effect on screen that consumes async that has not answered, the change is _held_: nothing of it shows, the screen keeps the content it had, and when every such async has landed, the change and all of it reveal as one frame. Which async counts: any new async that render effect consumes, whatever its source, unless a boundary catches the render effect (F-3, F-4). A first load in a branch the change mounts counts, and so does a memo created during the hold, when a render effect outside a boundary consumes it (D-2, D-6): the branch does not attach until they have answered, and the screen never shows it with an empty slot. `` is how a change escapes the hold. This is the navigation model: click, page B's data loads, page B appears whole. An `action` is the explicit form: its writes are held until its body has returned and everything they put in flight has landed.
+**Immutable.** When showing a change would put a render effect on screen that consumes async that has not answered, the change is _held_: nothing of it shows, the screen keeps the content it had, and when every such async has landed, the change and all of it reveal as one frame. Which async counts: any new async that render effect consumes, whatever its source, unless a boundary catches the render effect (F-3, F-4), or the async is a declared-lag source re-asking after its first answer (`createDeferred`, amended 2026-10-14): its readers keep the answer they show and hold nothing (D-40). A first load in a branch the change mounts counts, and so does a memo created during the hold, when a render effect outside a boundary consumes it (D-2, D-6): the branch does not attach until they have answered, and the screen never shows it with an empty slot. `` is how a change escapes the hold. This is the navigation model: click, page B's data loads, page B appears whole. An `action` is the explicit form: its writes are held until its body has returned and everything they put in flight has landed.
-**What it does not say.** It does not say that what an armed boundary catches makes the change wait (F-4: the catch is the exception, by design). It does not say a new memo joins a hold by being created — it joins by reading a held value, sync or async (D-2); a memo that reads nothing held or pending shows now. It does not say a display-ahead reader holds (F-6). It does not say the hold never waits on work that has never committed: that was the direction rule's time half (2026-10-06, #3820; drafted as F-8, withdrawn 2026-10-09 — the ID is not reused). A first load a render effect consumes outside a boundary holds the change like any other async.
+**What it does not say.** It does not say that what an armed boundary catches makes the change wait (F-4: the catch is the exception, by design). It does not say a new memo joins a hold by being created — it joins by reading a held value, sync or async (D-2); a memo that reads nothing held or pending shows now. It does not say a display-ahead reader holds (F-6), or that a declared-lag source's re-ask does (D-40); its first load does, like any. It does not say the hold never waits on work that has never committed: that was the direction rule's time half (2026-10-06, #3820; drafted as F-8, withdrawn 2026-10-09 — the ID is not reused). A first load a render effect consumes outside a boundary holds the change like any other async.
-**Collapses:** A15 (entanglement), A29 (the read entry, born held, ruling A), A26 (actions), A34 (1) (a write to a held slot joins), the tick ruling (2026-10-04), #3800's direction, the #2933 navigation model, recovery 2.1/3.1/3.2/4.2, the 2026-10-07 words "in general transitions can hold on any unready read". **Derived:** D-1–D-4, D-6–D-11, D-28. **Scenarios:** S-1–S-13, S-39.
+**Collapses:** A15 (entanglement), A29 (the read entry, born held, ruling A), A26 (actions), A34 (1) (a write to a held slot joins), the tick ruling (2026-10-04), #3800's direction, the #2933 navigation model, recovery 2.1/3.1/3.2/4.2, the 2026-10-07 words "in general transitions can hold on any unready read". **Derived:** D-1–D-4, D-6–D-11, D-28, D-40. **Scenarios:** S-1–S-13, S-39, S-41.
## F-3. A reader holds only while it is the display
@@ -129,7 +130,7 @@ These are the only words the fundamentals use. Internal names (transaction, stag
## Reading the fundamentals together
-- **What waits:** F-2 says a change waits for the async its on-screen content needs. F-3 removes a reader that is no longer the display. F-4 removes what an armed boundary catches from it — a transition's reads, or a lane's own async — and the boundary shows a fallback in its place. F-6 removes display-ahead readers from it.
+- **What waits:** F-2 says a change waits for the async its on-screen content needs. F-3 removes a reader that is no longer the display. F-4 removes what an armed boundary catches from it — a transition's reads, or a lane's own async — and the boundary shows a fallback in its place. F-6 removes display-ahead readers from it. A declared-lag source's re-asks never enter it (F-1, F-2, D-40).
- **What shows meanwhile:** F-1 says whatever shows is a whole frame. F-5 says a disarmed boundary's old content is that frame's. F-6 says display-ahead readers are the one way to show the change early; they bring their own derivations with them and hold themselves, in their own lane, on their own async. F-7 says nothing else from the change shows early.
- **Verdicts and visibility:** F-9 says when the screen admits it is stale. F-10 says when a write exists at all. F-11 says what an optimistic value is and for how long. F-12 says what an error is and is not.
diff --git a/packages/signals/docs/RULES-INDEX.md b/packages/signals/docs/RULES-INDEX.md
index 8640841552..00c5eca60c 100644
--- a/packages/signals/docs/RULES-INDEX.md
+++ b/packages/signals/docs/RULES-INDEX.md
@@ -52,23 +52,23 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul
| A5 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:351` | — | derived-write-then-derivation-3733.test.ts×1 errorHalt.test.ts×1 | [ruled] An error escaping every boundary halts the system — An error escaping every boundary permanently halts the system with `REACTIVITY_HALTED`; later writes log "Update ignored". |
| A6 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:359` | boundaries.ts×2 | derived-write-then-derivation-3733.test.ts×1 enforceLoadingBoundary.test.ts×1 | [ruled] `ASYNC_OUTSIDE_LOADING_BOUNDARY` is warn-only — `ASYNC_OUTSIDE_LOADING_BOUNDARY` is a warn-only diagnostic; an `Errored` above must not swallow it and must not show its fallback for a pending. |
| A7 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:165` | — | fuzz-findings-l2.test.ts×1 spec-async-semantics.test.ts×2 visibility-oracle-store.states.ts×1 visibility-oracle.states.ts×1 visibility-oracle.test.ts×1 | [ruled, amended in place] Resolved async never reads `[false, undefined]` — After an async memo resolves, `[isPending(x), latest(x)]` is `[false, resolvedValue]` — never `[false, undefined]`. **Amende… |
-| A8 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:173` | — | createMemo.test.ts×1 visibility-oracle-store.states.ts×1 visibility-oracle.states.ts×2 | [ruled, amended in place 2026-07-07] `isPending(() => latest(x))` follows `x`'s own async only — verdicts are per-channel — (**re-ruled 2026-07-07c** — was "tracks the transition the same as `isPendin… |
+| A8 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:173` | — | create-deferred-3710.test.ts×1 createMemo.test.ts×1 visibility-oracle-store.states.ts×1 visibility-oracle.states.ts×2 | [ruled, amended in place 2026-07-07] `isPending(() => latest(x))` follows `x`'s own async only — verdicts are per-channel — (**re-ruled 2026-07-07c** — was "tracks the transition the same as `isPendin… |
| A9 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:181` | projection.ts×1 target.ts×1 | spec-async-semantics.test.ts×3 visibility-oracle-store.states.ts×4 visibility-oracle-store.test.ts×1 | [ruled, amended in place 2026-07-07] Store leaves behind a firewall report the firewall's new-question refetch — `isPending` on a store leaf behind a firewall reports the firewall's refetch like any a… |
| A10 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:189` | core.ts×3 verdict.ts×2 | createMemo.test.ts×1 fuzz-findings-l2.test.ts×1 ispending-memo-unstamped-hold-3457.test.ts×2 latest-isPending-consistency.test.ts×3 verdict-contract.test.ts×2 | [ruled] `[isPending(x), x()]` is atomic within one scope — `[isPending(x), x()]` read in one scope is atomic: a reader that observed the fresh value must not see `pending === true` for it. |
| A11 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:103` | — | latest-isPending-consistency.test.ts×1 loading-fallback-in-flush-3540.test.ts×2 visibility-oracle-store.states.ts×2 visibility-oracle.states.ts×1 | [ruled] Sync derivations of held sources are visible through `latest()`/`isPending()` — Sync derivations of transition-held sources are visible through `latest()`/`isPending()` (held sync recompute is… |
| A12 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:197` | — | createOptimistic.test.ts×2 spec-async-semantics.test.ts×1 | [ruled, amended in place] Resting optimistic nodes report pending like a plain memo — A resting optimistic node reports pending via exactly the causes a plain async memo does (A19) — a reverting optim… |
| A13 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:205` | — | spec-async-semantics.test.ts×7 | [ruled 2026-07-06 (promoted from B1)] Resting optimistic ≡ plain async memo at every checkpoint — (was B1) A resting optimistic node (no active override) is observationally identical to a plain async … |
| A14 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:213` | — | spec-async-semantics.test.ts×1 | [ruled, amended in place 2026-07-06 (promoted from B2)] Companion nodes get child lanes that do not merge with the owner — (was B2) `isPending`/`latest` companion nodes get child lanes that do not mer… |
-| A15 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:249` | async.ts×2 constants.ts×1 core.ts×3 lanes.ts×4 scheduler.ts×14 verdict.ts×4 | async-chain-supersession.test.ts×1 boundary-output-frame-reader.test.ts×1 first-observer-stale-reader.test.ts×1 fuzz-findings-l2.test.ts×17 held-restore.test.ts×1 l2-contract.test.ts×7 l2-fuzz-existing-rules.test.ts×2 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 loading-fallback-in-flush-3540.test.ts×4 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 … |
+| A15 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:249` | async.ts×2 constants.ts×1 core.ts×3 lanes.ts×4 scheduler.ts×14 verdict.ts×4 | async-chain-supersession.test.ts×1 boundary-output-frame-reader.test.ts×1 create-deferred-3710.test.ts×2 first-observer-stale-reader.test.ts×1 fuzz-findings-l2.test.ts×17 held-restore.test.ts×1 l2-contract.test.ts×7 l2-fuzz-existing-rules.test.ts×2 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 loading-fallback-in-flush-3540.test.ts×4 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:221` | 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:71` | async.ts×3 constants.ts×1 lanes.ts×7 scheduler.ts×2 verdict.ts×1 map.ts×1 store.ts×3 | fuzz-findings-l2.test.ts×6 lane-uninitialized-landing-3648.test.ts×5 optimistic-over-held-row-3796.test.ts×1 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… |
+| A17 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:71` | async.ts×3 constants.ts×1 lanes.ts×7 scheduler.ts×2 verdict.ts×1 map.ts×1 store.ts×3 | create-deferred-3710.test.ts×1 fuzz-findings-l2.test.ts×6 lane-uninitialized-landing-3648.test.ts×5 optimistic-over-held-row-3796.test.ts×1 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:81` | 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 l2-fuzz-existing-rules.test.ts×2 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×5 flight-owned-transaction.test.ts×1 lane-authority-twins.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:149` | async.ts×1 constants.ts×1 core.ts×6 scheduler.ts×2 types.ts×1 verdict.ts×4 store.ts×1 | fuzz-findings-l2.test.ts×4 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… |
+| A19 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:149` | async.ts×1 constants.ts×1 core.ts×6 scheduler.ts×2 types.ts×1 verdict.ts×4 store.ts×1 | create-deferred-3710.test.ts×2 fuzz-findings-l2.test.ts×4 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:408` | — | 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:415` | — | 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… |
| A22 | amended | `docs/SPEC-ASYNC-SEMANTICS.md:229` | store.ts×1 | createProjection.draft-lifetime-3585.test.ts×1 spec-async-semantics.test.ts×1 visibility-oracle-store.states.ts×1 | [ruled, amended in place 2026-07-08] Pending is per-node; store-wide only for the firewall's own work — **Pending is per-node: store-wide verdicts exist only as the firewall's own in-flight work (A9) … |
| A23 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:239` | — | spec-async-semantics.test.ts×1 | [ruled 2026-07-08] The `isPending` probe is reads-only — **The `isPending` probe is reads-only — the thunk's return value is never inspected.** `isPending(() => store)` reads nothing and reports `fals… |
-| A24 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:157` | affects.ts×2 constants.ts×1 lanes.ts×2 types.ts×1 verdict.ts×3 affects.ts×1 optimistic.ts×1 | body-end-supersession-visibility.test.ts×1 optimistic-undefined-override.test.ts×1 reveal-gating-contract.test.ts×1 spec-async-semantics.test.ts×3 kanban-a17-fixture.test.ts×1 signal-store-twins-qd.test.ts×1 visibility-oracle-store.states.ts×4 visibility-oracle.states.ts×5 visibility-oracle.test.ts×1 | [ruled 2026-07-13] Question-scoped pending: pending iff a value change is in flight or an `affects()` mark is live — (**ruled 2026-07-13** — supersedes A20/A21; the converged model from the #2844/#272… |
+| A24 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:157` | affects-marks.ts×1 affects.ts×1 constants.ts×1 lanes.ts×2 types.ts×1 verdict.ts×3 affects.ts×1 optimistic.ts×1 | body-end-supersession-visibility.test.ts×1 create-deferred-3710.test.ts×2 optimistic-undefined-override.test.ts×1 reveal-gating-contract.test.ts×1 spec-async-semantics.test.ts×3 kanban-a17-fixture.test.ts×1 signal-store-twins-qd.test.ts×1 visibility-oracle-store.states.ts×4 visibility-oracle.states.ts×5 visibility-oracle.test.ts×1 | [ruled 2026-07-13] Question-scoped pending: pending iff a value change is in flight or an `affects()` mark is live — (**ruled 2026-07-13** — supersedes A20/A21; the converged model from the #2844/#272… |
| A25 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:309` | projection.ts×2 | derived-presence-async-3726.test.ts×2 seedless-derived-store.test.ts×1 uninitialized-visibility.test.ts×3 visibility-oracle-store.states.ts×7 visibility-oracle-store.test.ts×1 | [ruled 2026-07-16] A derived store's seed is a draft, never an observable value — (**ruled 2026-07-16**, #2897) **A derived store's seed is a draft, never an observable value.** The seed exists for th… |
| A26 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:111` | — | action-await-contract.test.ts×2 fuzz-findings-l2.test.ts×1 posture-store-parity.test.ts×2 visibility-oracle-store.states.ts×2 visibility-oracle.states.ts×1 visibility-oracle.test.ts×1 | [ruled 2026-07-17] An ambient transaction window is one flush; parking is flush-driven — (**ruled 2026-07-17**, #2913; **enforcement hardened 2026-08-31**, #3141 — parking is flush-driven, and a trans… |
| A27 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:301` | — | loading-value.test.ts×2 visibility-oracle.states.ts×18 visibility-oracle.test.ts×1 | [ruled 2026-08-10] The commit-#0 loading window is loading-class and verdict-quiet — (**ruled 2026-08-10**) **The commit-#0 loading window is loading-class and verdict-quiet.** A node born committed v… |
@@ -77,7 +77,7 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul
| A30 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:257` | async.ts×3 attribution.ts×1 constants.ts×1 core.ts×1 effect.ts×1 lanes.ts×1 scheduler.ts×5 | async-landing-deps-3461.test.ts×3 fuzz-findings-l2.test.ts×3 held-conditional-effect.test.ts×1 held-conditional-memo.test.ts×1 held-frame-dependencies.test.ts×2 ispending-in-boundary-on-3528.test.ts×1 lane-frame-deferred-run-3662.test.ts×1 lane-frame-held-lane-3662.test.ts×1 posture-born-held-and-observation.test.ts×1 treeshake.test.ts×2 write-proposals-3494.test.ts×2 zombie-rerun-after-commit-3546.test.ts×2 | [ruled 2026-09-13 (#3410)] A memo's dependencies are the committed frame's until the frame is replaced — A pass that _staged_ its value has not replaced the committed frame, so the committed value sti… |
| A31 | live | `docs/SPEC-ASYNC-SEMANTICS.md:131` | boundaries.ts×1 core.ts×1 lanes.ts×1 verdict.ts×2 | fuzz-findings-l2.test.ts×6 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:139` | 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:273` | boundaries.ts×1 scheduler.ts×2 | async-chain-supersession.test.ts×2 boundary-not-born-held-3540.test.ts×2 fuzz-findings-l2.test.ts×4 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 `` boundary showing its fallback is the display of everything un… |
+| A33 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:273` | boundaries.ts×1 scheduler.ts×2 | async-chain-supersession.test.ts×2 boundary-not-born-held-3540.test.ts×2 create-deferred-3710.test.ts×1 fuzz-findings-l2.test.ts×4 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 `` boundary showing its fallback is the display of everything un… |
| A34 | ruled | `docs/SPEC-ASYNC-SEMANTICS.md:283` | 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 fuzz-findings-l2.test.ts×5 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
@@ -119,7 +119,7 @@ Status legend: **live** stated and standing · **ruled** carries an explicit rul
| INV-8 | retired | `docs/INTERNALS-ASYNC-STATE.md:195` | invariants.ts×1 | rules-index.test.ts×1 | - **INV-8 (RETIRED 2026-07-07b, §5e)** Hold-provenance: a `_pendingValue` on an |
| INV-9 | live | `docs/INTERNALS-ASYNC-STATE.md:206` | — | inv4-projection-dispose-shadow.test.ts×1 | - **INV-9 (high)** An `isPending` companion of a DISPOSED owner reads `false` |
| INV-10 | live | `docs/INTERNALS-ASYNC-STATE.md:211` | — | action-done-window.test.ts×1 | - **INV-10 (high)** Affects-count balance (question-scoped model, 2026-07-13; |
-| INV-11 | live | `docs/INTERNALS-ASYNC-STATE.md:216` | core.ts×1 | spec-async-semantics.test.ts×1 treeshake.test.ts×1 | - **INV-11 (high, structural — pinned, not asserted)** A recompute's equality |
+| INV-11 | live | `docs/INTERNALS-ASYNC-STATE.md:216` | core.ts×1 | create-deferred-3710.test.ts×1 spec-async-semantics.test.ts×1 treeshake.test.ts×1 | - **INV-11 (high, structural — pinned, not asserted)** A recompute's equality |
## RUL — store rulings
| id | status | defined | cited in src | cited in tests | statement (at definition) |
diff --git a/packages/signals/docs/SCENARIOS.md b/packages/signals/docs/SCENARIOS.md
index fbcdc23ce4..40dc4ecdca 100644
--- a/packages/signals/docs/SCENARIOS.md
+++ b/packages/signals/docs/SCENARIOS.md
@@ -814,3 +814,28 @@ const data = createMemo(() => fetchOrFail(count())); // rejects for every co
| ✗ | | after 1: `1 \| loading` (the error clearing for a pending); or `0` held by the errored flight | |
`` never catches a pending: `ASYNC_OUTSIDE_LOADING_BOUNDARY` is a warning (A6).
+
+## F. Declared lag (D-40)
+
+### S-41. Independent panels over one selection: the write shows now, each panel lags to its own landing — D-40
+
+_Pinned: `tests/create-deferred.test.ts`._
+
+```tsx
+const [period, setPeriod] = createSignal(1);
+const fast = createDeferred(() => fetchFast(period())); // lands in 200ms
+const slow = createDeferred(() => fetchSlow(period())); // lands in 10s
+
+
+ );
+}
+
// ---------------------------------------------------------------------------
// 10b. Async memo under Loading that settles BEFORE the shell flush. Every
// other async scenario sleeps, so the boundary always takes the streaming
@@ -2399,6 +2426,15 @@ export const scenarios: Scenario[] = [
expectedTextAfterUpdate: "Value: 43",
stableSelector: "div"
},
+ {
+ name: "deferred-settled-element",
+ App: DeferredSettledDiv,
+ async: true,
+ expectedText: "Value: 42",
+ update: () => refreshDeferredDiv(),
+ expectedTextAfterUpdate: "Value: 43",
+ stableSelector: "div"
+ },
{
name: "async-inline-settled",
App: AsyncInlineSettled,
diff --git a/packages/web/test/hydration/create-deferred-lag.spec.tsx b/packages/web/test/hydration/create-deferred-lag.spec.tsx
new file mode 100644
index 0000000000..d10991e9e1
--- /dev/null
+++ b/packages/web/test/hydration/create-deferred-lag.spec.tsx
@@ -0,0 +1,87 @@
+/**
+ * @jsxImportSource @solidjs/web
+ * @vitest-environment jsdom
+ *
+ * `createDeferred` through SSR and hydration (docs/create-deferred.md D5,
+ * D7): the server renders it as the memo it wraps, the client claims the
+ * server-rendered content as commit #0 (the parity harness pins the claim
+ * over the same artifact — scenario "deferred-settled-element"), and the
+ * first refetch after hydration is already clamped: the claimed DOM keeps the
+ * adopted answer while the flight is up, and swaps at the landing. The
+ * `createMemo` twin (scenario "async-settled-element") would hold the
+ * update and show the new value only at the landing too — what differs is
+ * invisible to a textContent check at the end, so this spec reads the DOM
+ * MID-flight.
+ *
+ * Replays the chunk artifact test/server/hydration-harness.spec.tsx writes
+ * (loaded mode: the full-page refresh case).
+ */
+import { describe, expect, test, vi } from "vitest";
+import { existsSync, readFileSync } from "node:fs";
+import { resolve, dirname } from "node:path";
+import { fileURLToPath } from "node:url";
+import { flush } from "solid-js";
+import { hydrate } from "@solidjs/web";
+import { scenarios } from "../harness/scenarios.jsx";
+
+const artifactsDir = resolve(dirname(fileURLToPath(import.meta.url)), "../harness/__artifacts__");
+const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
+
+function loadArtifact(name: string): { shell: string; rest: string } {
+ const file = resolve(artifactsDir, `${name}.json`);
+ if (!existsSync(file)) {
+ throw new Error(
+ `Missing artifact for scenario "${name}". Run the server harness first: ` +
+ `vitest run --config vite.config.server.mjs test/server/hydration-harness.spec.tsx`
+ );
+ }
+ return JSON.parse(readFileSync(file, "utf-8"));
+}
+
+function applyChunk(container: HTMLDivElement, chunk: string, first: boolean) {
+ const scriptRe = /