--- status: historical created: 2026-08-18 archived: 2026-08-18 reason: "Stage-C evidence: the design pass's SPEC-ONLY lens (blind to code) on the demand walk (d) and the intent watch (e) — what the ruled sentences REQUIRE vs DESCRIBE, the no-lazy-demand chain, eleven flagged silences (S6), the counters the spec would want, the proposed amended serving-loop §1 sentence; read against fb2292a24; input to the reconciled design (docs/plans/server-execution-v2/stage-c-design.md)." --- I've read the named spec sections in full (scopes.md whole; serving-loop.md §1, §3, §3b, §3c–§3d as needed, §7, §8; protocol.md §1, §2, §3, §4, §5, §7; speculation.md whole; events.md §1–§5; key-vocabulary.md §1–§2; verification-coverage.md OW24/OW32). Findings follow, spec text only. # Findings — spec-only lens on the demand walk (d) and the intent watch (e) Legend: **V** = verified in the text at the cited line; **I** = my inference from the text (stated as such). ## S1. The demand walk: what the spec REQUIRES vs what it DESCRIBES ### (i) Requirements (binding or ruled semantics) 1. **A watch is identity-bearing demand for the subscriber's own instances.** scopes.md:161-167 (RULED 2026-08-16): a principal's demand at a broad address "is demand for THAT principal's instance of every node that narrows beneath it"; the registry records the (user, session) pair on space-scoped roots too; "every watch a client holds is identity-bearing demand". Restated serving-loop.md:53-59. **V** 2. **Demand = value-granular pull that recomputes the value AND ITS UPSTREAM for the subscriber's instances, nothing else.** serving-loop.md:53-55. **V** 3. **Instances = discovered scope × demanders (per-node rule).** scopes.md:167-175 and serving-loop.md:371-383: while a node has read nothing scoped it "runs ONCE, as a PROBE ... regardless of demander count"; once user is discovered, once per demanding principal; once session, once per demanding session of that principal (ragged). Discovery re-arm (same wave, serving-loop.md:383-386; scopes.md:176-178) and arrival re-arm "for that pair only" (serving-loop.md:386-387; scopes.md:178-181). **V** 4. **Demanded instances must be current before W advances; undemanded stay dirty-unmaterialized.** protocol.md:651-655 (W definition), :670-679 ("every DEMANDED INSTANCE of every demanded node"; a later arrival is ordinary later demand); serving-loop.md:62-66, :197-198, :223-230 (idle() awaits demanded pull work, not undemanded computeds); scopes.md:142-149. **V** 5. **Per-demander run identity.** scopes.md:317-320: a derivation runs per demanded instance and the demand supplies the identity; scopes.md:262-270 (client speculates own instances only). **V** 6. **B7 / C11b.** serving-loop.md:388-398: the node is singular (C11b); per-instance last log + clean bit; "a change dirties exactly the instances whose reads covered it"; "a space doc dirties all"; the node's ONE subscription is the union of the instance logs, "a pass that skips clean instances keeps their reads registered"; an N-user space costs O(affected instances) per change, "the load-bearing property". **V** 7. **Coverage is what the rest of the spec relies on.** speculation.md:117-121, :133 name "any per-user subtree the demand walk does not reach" / "demand-walk coverage gaps" as the failure the arrival gate backstops. The walk's REACH is the operative concept elsewhere; its run count/frequency is referenced nowhere else. **V** 8. **Positive tripwire on liveness.** serving-loop.md:1190-1207: liveness is maintained incrementally, "NO global rebuild runs on the maintenance path"; new demand-root kinds or registration flips MUST bracket transitions with `wasLive`/`notifyNodeLivenessChange` (or `setNodeProvisionalDemand`) and pass `SCHEDULER_LIVENESS_EQUIVALENCE=1`. **V** ### (ii) The mechanism sentence serving-loop.md:59-62: "the demand WALK (the live reader per demanded root that pulls the value's subtree) runs once per demanding pair, each run following THAT demander's redirects." Reading (my judgment, from the text): - **Not a MUST/NEVER sentence.** serving-loop.md:6 makes MUST/NEVER the binding vocabulary; this sentence carries neither. **V** - **Structurally a consequence clause of the ruling, not the ruling.** It is introduced by "so … and" after "(scopes.md §2, RULED 2026-08-16; fan-out stage B)"; scopes.md:161-163 splits the same item into "RULED … design §A/§I.1" (the semantics) and "landed by fan-out stage B" (the mechanism). The parenthetical uses implementation vocabulary ("live reader", "pulls"). **V/I** - **A normative reading would make the spec self-inconsistent.** The ruled per-node instancing rule (scopes.md:169-172; serving-loop.md:380-383) says unnarrowed structure runs ONCE regardless of demander count. A walk that fans out per pair over unnarrowed space-scoped structure is the one thing in the spec that does NOT follow that rule. **I** (strong) - **The semantic residue that IS load-bearing:** "each run following THAT demander's redirects" — whose instance chain a walk follows (matches scopes.md:167-181 and §5:317-320). Keep that; the cardinality clause is mechanism. **Minimal thing the spec needs the walk to establish:** that every node reachable from a demanded root — for each demander's OWN instances (space nodes once; scoped nodes per demander per the ratchet) — is LIVE, i.e., recomputed when dirty before idle()/W (items 2–4), following each demander's own redirects, with late arrivals re-armed for that pair only (item 3) and the event actor's transient demand honored (scopes.md:186-198). Nothing more. **V+I** **Re-run frequency:** the spec NEVER states when the walk re-runs. No sentence says "on every commit under the root". The only text that could imply per-change re-run is §3b's generic node rule (serving-loop.md:328-329, last run's read set) IF the walk is modelled as a run — but §3b enumerates the run kinds as "handler, computed, eager action" (:326), and the walk is none of these; it is a demand-root mechanism whose product is liveness/registration. **V** (absence) **+ I** **Does §3b constrain an incrementally maintained walk subscription?** No — it sanctions the pattern: B7 keeps clean instances' reads registered without re-running them (:392-394), and the one-run-late argument (:330-334) transfers to the walk: the reachable set can only gain C through a change in something already read — a link/redirect-bearing path the walk logged, or a reachable node's own re-run (which the node registers itself, :328-329, and liveness propagates incrementally, :1190-1207). A walk registered at path precision on link-bearing reads (path precision is in-memory, :477-479) is exactly as sound as one-run-late. **I** **Does "a space doc dirties all" apply necessarily to a write-nothing walk?** No. B7 is stated for derivation nodes with per-instance OUTPUTS whose correctness depends on the space doc. For the walk, (a) under the ruled per-node instancing the walk over space structure has ONE instance (probe), so "all" = one; (b) "dirties" only means "marks for recompute when demanded" — nothing in B7 makes re-running a write-nothing node the required way to maintain its registration; its registration persists across passes by B7's own union rule. Note also B7's stated purpose — O(affected instances) per change, never O(N) per node (:394-396) — is VIOLATED by a per-pair walk re-run over shared structure; the redesign restores B7's property for the walk. **I** **One correction to the redesign framing:** the shared/per-pair split is not a clean prefix/suffix. Space-scoped nodes are shareable wherever they occur (a user-scoped instance may link back into space docs); scoped instances are per-demander. Model the walk on the spec's node rule: one probe over any unnarrowed node, fork per demanding principal at a discovered space→user redirect (shared state at space, scopes.md:203-207 — so identical for all demanders), fork per demanding session of THAT principal below it (ragged, scopes.md:207-215; do NOT assume a uniform suffix shape). Node-level sharing (two roots reaching one space node) is consistent with C11b. **I** **Sentence(s) a redesign would need to AMEND** — only serving-loop.md:57-62; scopes.md §2 needs at most a cross-reference. Proposed text for serving-loop.md:57-62: > …so the demand registry keeps the demanding (user, session) pair on every root a client watches, space-scoped roots included, and the demand WALK (the live reader per demanded root that establishes the value's reachable subtree as live) is instanced like any node (scopes.md §2): ONE probe over unnarrowed structure regardless of demander count, forking per demanding principal at a discovered space→user redirect and per demanding session of that principal below it (ragged), each fork following THAT demander's redirects. What the walk MUST establish is COVERAGE: every node reachable from the root, for each demander's own instances, is live — recomputed when dirty before W advances (protocol.md §4). It re-walks on STRUCTURAL change only — a write at a link- or redirect-bearing path in its own last-run read set, a narrowing discovered beneath it (the discovery re-arm), or a demanding pair's arrival (the arrival re-arm, that pair's forks only) — never on a value-only change, which reaches the affected nodes through their own subscriptions (§3b, B7). Its registration is maintained incrementally and never rebuilt (§8's liveness tripwire); its runs and skips are counted (§7). Optionally append to B7 (serving-loop.md:398): "(The demand walk over unnarrowed structure has ONE instance by §1, so 'a space doc dirties all' costs one walk, not one per demander.)" ## S2. Laziness ruling (per-demander projection computed on first read / next pull) Reasoning chain: a watching pair IS a demander (scopes.md:165-167; serving-loop.md:57-59) → its instances are DEMANDED → W "advances only when every DEMANDED INSTANCE of every demanded node" is current (protocol.md:670-679; :651-655) → a demanded-but-not-computed instance while W advances is a violation of W's definition. The ratchet ("known scope only narrows", scopes.md:219-222) is not the issue; W is. Deferring the pair's instance while HOLDING W is permitted but pins W for everyone (serving-loop.md:395-398: a pinned W "stalls the client's coverage-of-basis retirement") and violates nothing — but is the opposite of a saving. Redefining "current" to admit lazy-on-read breaks the client's settled contract (protocol.md:667-669) and the arrival-gate premise that "the demanded derivation exist[s] and land[s]" (speculation.md:113-119) — the OW32 retire-to-nothing loop is precisely the spec's record of what an unserved-but-watched instance does (speculation.md:117-127; verification-coverage.md:2687-2714). **V+I** What the spec says about leaving/arriving: arriving = arrival re-arm for that pair only, "ordinary later demand" (scopes.md:178-181; protocol.md:676-678). Leaving is thin: demand exists while a watch exists (serving-loop.md:57-59, implied), session retirement (scopes.md:239-260), the departed session's stranded basis rows (serving-loop.md:503-504). **No "idle demander" tier exists anywhere in the read text**; the only idle concept is space-level parking (serving-loop.md:44-46, :250-251). **V** (grep-verified absence) **OWNER RULING — proposed options:** - **A. No laziness for a watching pair (spec as written).** Every watch is full demand; W waits. Cost is fixed on the mechanism (S1). *Recommended.* - **B. Client-side demand hygiene, no server tier.** A client that goes idle (hidden tab) DROPS its watches → leaves D → its instances become undemanded (free, protocol.md:653-655) → on return, arrival re-arm. Zero spec change; this is the demand-driven laziness the spec already has. *Recommended as the ONLY laziness.* - **C. Server-side "idle demander" tier.** A pair not pulling for T is demoted from D with an explicit re-arm on next pull. Needs edits to scopes.md §2 (:161-198), serving-loop.md §1, protocol.md §4 (W's demanded set), plus a client contract that "settled" is undefined while demoted. Not recommended: it recreates the unserved-instance class the arrival gate exists to backstop. - **D. Lazy compute, W held.** Sound, useless (pins W). ## S3. The client intent watch: exact requirements, minimal state, minimal signal **What is required (V):** - speculation.md:79-86 (§4 step 2): "On each pushed `derived` commit with `derivedThrough = W` and `consequenceOf = [E...]`" retire overlay entries with `origin = intent(e)` for e ∈ E — the consequences "(or, for a dropped event, its notice — events.md §5) now exist". - step 4 (:97-99): if local intents remain un-consequenced, re-run their speculation against fresh store state — assigned to RECONCILIATION on each push, not to any watch. It costs O(outstanding intents) speculation re-runs per push, bounded by §5:192-193. - §5:181-193: dropped notice (eventId + reason) retires the event's overlay entries and "is the UI's hook to react"; "Overlay memory is bounded by pending-intent count". - events.md:269-271: a dropped event's client "MUST be signaled so the UI can react"; T7 (:285-294): the notice `{status:"dropped", reason}` is a FIELD ON THE STREAM DOC'S OWN ENTRY, "written as that event's consequence and advancing eventWatermark past it"; retires with its entry on compaction. Handler error (:244-247): error surface "as the derived commit for that event", eventWatermark advances. - Commit metadata `consequenceOf` is MANDATED and the complete list is closed: events.md:212-213; protocol.md:773-775; serving-loop.md:233. The split rule (serving-loop.md:294-303) is designed so "the split a client happens to receive must itself carry the eventIds its overlay reconciliation matches" — the spec DESIGNS reconciliation around commit metadata. serving-loop.md:272-275: echoes retire on the FIRST flush because consequenceOf carries them. **Minimal state:** the outstanding eventId set is ALREADY the overlay's `origin = intent(eventId)` entries (speculation.md:22-23) — no separate state; bounded per §5:192-193. **V** **Minimal signal per pushed derived commit:** `consequenceOf ∩ outstanding`. Backstops that are also spec facts: `eventWatermark ≥ seq(e)` on the stream doc (events.md:214-216: seq of the last event whose consequences committed; atomic with them, :220-223) and `W ≥ seq(e)` (protocol.md:651-653: every authored commit ≤ W has all handler consequences committed). Both are O(1) fields, neither is per-entry history. Only the DROP REASON requires reading a value-plane entry — the tracked event's own entry, by eventId (T7). **V+I** (I infer stream seq = the append's space seq from events.md:165-167/:217-218 + protocol.md:667; not stated explicitly.) **Not required by any sentence (V by absence, grep-checked):** a reactive scheduler effect for the watch; reading the sidecar's entries' payloads; reading the whole sidecar; a per-fire CFC label probe (speculation.md has no CFC/label/reactive text at all; §3c's read-time label derivation applies to RUNS reading cells, serving-loop.md:652-656 — so the probe cost is a CONSEQUENCE of making the watch a run, which nothing mandates); a `consequenced` mark on entries (the word appears only adjectivally, speculation.md:23, events.md:304-305 — no such field is specified anywhere). **Where the consequence signal lives:** metadata (`consequenceOf`, mandated) is the reconciliation key; the value plane holds `eventWatermark` (mandated field on the stream doc) and the drop notice/error surface (mandated, on the entry). Both planes are mandated for their respective purposes; a per-entry `consequenced` mark is in neither. Note events.md:239-240 FORBIDS "a processed-events table; per-event acks from clients; handler-run provenance records" and §4:224-230's compaction allowance is the spec's reason per-entry marks are unnecessary. **V** **Watermark backstop / acceptable to miss a signal?** The spec states step 2 as an obligation per push, and scopes coverage-based retirement honesty to input entries (speculation.md:106-110). It never says the watch MAY miss consequenceOf. But since W ≥ seq(e) and eventWatermark ≥ seq(e) are both spec-defined "consequences committed" facts, a missed frame caught by the sweep's coverage rule satisfies the SEMANTICS ("the echo's job is done"). Same coupling assumption as the arrival gate (speculation.md:147-156). → owner ruling (S6 #9). One spec-recorded hazard for a non-reactive listener: the ack-after-covering-watermark wake (speculation.md:239-247) — the listener must also wake on origin acks, or entries stay pending forever. **V** **Compaction robustness (spec-side argument for tracked-only):** outstanding intents are by definition above eventWatermark and therefore above the compaction line (events.md:228-229); a tracked-entry watch never reads compactable data, while a whole-history watch reads exactly what "MAY compact" and depends on OW24's unpinned skip-vs-re-execute behavior (verification-coverage.md:1376-1388). **V+I** **What a tracked-only / non-reactive redesign must amend:** nothing normative. speculation.md:171-175 are impl anchors, not requirements; :147-150 describes the input-origin sweep's triggers (unchanged). Recommend adding one clarifying sentence to §4 step 2: "the match is on the pushed commit's `consequenceOf`; the entry is read only for a dropped event's reason." ## S4. Tripwires a redesign of (d) or (e) could trip scopes.md §9 (:519-536): - :522-524 scope selects who runs/commits — (d) no (one SpaceServer/scheduler still runs all); (e) n/a. - :525-526 client committing a scoped derived instance — (e) no. - :527-528 "ragged instance sets as a steady state" — (d) sketch that assumes a uniform per-demander suffix would violate §2's AMENDED ragged ruling (:199-222) rather than this tripwire; **spec inconsistency**: §9 still forbids what §2 now permits below the top hop (S6 #10). - :529-530 static scope inference feeding fan-out — **(d) TRIPS if the structural-change gate classifies commits by schema/code** ("this field can't be a link"). Safe only as evidence-from-reads: "did a commit write a path in the walk's own logged link/redirect-bearing read set?" (D11, scopes.md:89-94; serving-loop.md:323-329, path precision :477-479). - :531-533 per-scope/per-instance watermarks — **(d) TRIPS if per-pair "current through seq X" bookkeeping gates or forks W**; use B7's per-instance CLEAN BIT (serving-loop.md:389-390), never a seq W consults. (e) n/a. - :534-536 context ladder — no. serving-loop.md §8 (:1165-1207): - Lexical (:1170-1175): avoid identifiers `claim`, `candidate`, `settlement`, `rank`, `evidence`, `shadowRun` in NEW code — (d) risk: "candidate demanders", "rank the smallest pair" (spec says "smallest", :380-381); (e) risk: `settlement` (prose uses "chained settlements", speculation.md:150 — don't make it an identifier). Neither sketch needs them. - Positive liveness tripwire (:1190-1207): **(d) is DIRECTLY implicated** — the shared-probe/per-fork walk and incremental union subscription change how liveness derives from demand roots; every transition (pair arrival/departure, fork, structural re-walk) MUST be bracketed (`wasLive` → `notifyNodeLivenessChange`, or `setNodeProvisionalDemand`) and the equivalence hook must stay green. Unbracketed = "SILENT" starvation. Would trip if skipped. Conversely, per-change full re-walks are the "global rebuild" posture this tripwire disfavors in spirit — the redesign moves TOWARD it. speculation.md §6 (:195-247): - :197-201 derived commit / handler write / effectful builtin / persist overlay / send overlay contents / "server is wrong" — (e) sketch trips none, PROVIDED the outstanding set stays process-local (never persisted, §1:24-25) and is never sent as a "which of mine are done?" query (events.md:239-240's per-event-ack ban is the neighboring hazard). - :203-225 process-local principle / export refusal — untouched. - :239-247 retirement wake — not FORBIDDEN, but the recorded pending-forever bug: a non-reactive listener must still wake on origin acks AND each pushed derived commit. events.md §4:239-240 (not in the asked list, relevant): a client-side outstanding set is not a processed-events table (it is the PENDING set, bounded, drains to zero); a design that RELIES on a server-side per-entry `consequenced` mark is arguably a handler-run provenance record — flag (S6 #6). ## S5. Counters the spec would want (serving-loop.md §7 :1112-1163: "implement with the loop, not after"; "tests MUST assert on counters, not logs") None of §7's counters can see the (d) term (:1115-1125 list; only `wavesBudgetExhausted` shows it indirectly). Propose a `demand` block under `servingLoop`: `roots`, `pairs`, `walkRuns` (total), `walkProbeRuns` (shared/unnarrowed), `walkForkRuns` (per principal / per session), `walkStructuralTriggers`, `walkValueOnlySkipped` (commits that dirtied a walk's read but touched no link/redirect-bearing path — the gate's witness), `walkArrivalRearms`, `walkDiscoveryRearms`, `actorPreflightRearms` (scopes.md:191-197), `registeredReads` gauge (union-subscription size, current/max) — plus the two spec-named counters §7's list omits: `undemandedNarrowingRuns` (scopes.md:186) and `earlyEmitRefusals` (protocol.md:280) (drift; fold them in). For (e), the read files carry NO client counter contract; recommend a `commonfabric.*` debug surface: `pendingIntents`, `intentRetiredByConsequenceOf`, `intentRetiredByBackstop`, `dropNoticesSeen`, `errorNoticesSeen`, `sidecarEntriesRead` (must be O(tracked), never O(history)) — and pin it in the speculation tests (the spec's precedent: `speculation-arrival-gate.test.ts`, speculation.md:175). ## S6. Silences — flag, don't fill (owner rulings; options + recommendation) 1. **Is "runs once per demanding pair" normative?** Options: (a) descriptive of stage B — replace with the S1 amended sentence; (b) normative — then (d) is a spec change and the spec is inconsistent with its own per-node probe rule (scopes.md:169-172; serving-loop.md:380-383). *Recommend (a).* 2. **Must a value-only change re-run the walk?** Spec silent. (a) any dirtying change (walk-as-node); (b) structural only — link/redirect-bearing path in the walk's own read log, discovery re-arm, arrival re-arm — evidence-from-reads only; (c) (b) plus a periodic full re-walk belt (a global rebuild; against §8's spirit). *Recommend (b), with "structural" defined from the walk's logged reads (D11-safe).* 3. **Must the intent watch be a reactive scheduler effect?** Silent; §4 is written as a per-push procedure. *Recommend no: a listener at the replica-apply boundary over `consequenceOf` + the outstanding set, also woken by origin acks (speculation.md:243-247).* 4. **Must the sidecar be read at all?** Retirement keys on mandated metadata; only the drop reason lives on the entry. *Recommend: read the tracked entry only, on drop, for the UI hook; never whole-history; add the clarifying sentence to §4 step 2.* 5. **May an "idle demander" tier exist?** See S2. *Recommend no server tier; client drops watches when idle.* 6. **Is a per-entry `consequenced` mark sanctioned?** Not in the spec; eventWatermark already carries consequenced-ness. *Recommend: not a client dependency; if it exists it compacts with its entry (T7 semantics) and events.md §4:239-240 is the test it must pass.* 7. **Do dropped/errored eventIds appear in `consequenceOf`?** Inferred from "every eventId drained this wave" (serving-loop.md:233) + drops/errors advancing eventWatermark (events.md:246-247, :288-289) — never stated for those two cases. *Recommend a one-line pin in events.md §5 (same style as OW24's owed sentence).* 8. **Is the client GUARANTEED to receive the frame carrying `consequenceOf` for its own event?** Silent. Delivery vehicle in practice: the eventWatermark write on the stream doc the client appended to. *Recommend pinning: a client keeps each stream with outstanding intents subscribed until that stream's outstanding set is empty — which is exactly the minimal watch.* 9. **Backstop ruling:** may an intent-origin entry retire on `W ≥ seq(e)` or `eventWatermark ≥ seq(e)` when the consequenceOf frame was missed? Both are spec-defined "consequences committed" facts (protocol.md:651-653; events.md:214-216). *Recommend yes; W-coverage is the sweep's existing rule, so one sweep serves both origins.* 10. **Spec inconsistency:** scopes.md §9:527-528 forbids "ragged instance sets as a steady state"; §2:199-222 (amended 2026-08-16) permits ragged below the space→user hop "simultaneously and stably". *Recommend amending §9 to "ragged at the space→user hop".* 11. **Does a write-nothing walk record basis rows?** §3b's rows are per (action, instance) output-currency (serving-loop.md:399-408, :472-476); a walk has no output, and activation re-walks demanded roots by construction (:197-198). *Recommend no basis rows for the walk; say so in §3b to keep recovery from re-marking a zombie.* Verified vs inferred summary: every quoted requirement and every "absence" claim above was checked against the cited lines (grep for walk/demander/sidecar/consequenced/idle/label across the named files); the judgments that (i) the mechanism sentence is descriptive, (ii) B7 need not apply to the walk, (iii) the shared probe is sound by top-hop monotonicity, (iv) drops/errors ride `consequenceOf`, and (v) stream seq = append seq are inferences from the text, marked I above.