Skip to content

feat: per-channel initial-state opt-out for reactive-only channels (R-040, D-025) - #9

Merged
nzneit merged 17 commits into
mainfrom
initial-state-optout
Aug 2, 2026
Merged

feat: per-channel initial-state opt-out for reactive-only channels (R-040, D-025)#9
nzneit merged 17 commits into
mainfrom
initial-state-optout

Conversation

@nzneit

@nzneit nzneit commented Aug 2, 2026

Copy link
Copy Markdown
Owner

What

topicOverrides.<address>.initialState: false in services.yaml declares a reactive-only channel (error/notification topics): the L1 floor never materializes initial state there, on any leg (concrete subscribe, eager startup, seedInstances, reset republish), while the instance ledger, L2/L3 emissions, wildcard retained replay, and the explicit example surfaces stay untouched.

Fixes the class of bug where a stateful client's state machine is corrupted by a synthetic schema-valid example arriving on a topic that should be silent until something real happens (a real broker delivers nothing on subscribe to a non-retained topic).

Design decisions (docs/archive/intake/2026-08-01-initial-state-optout.md, D-025)

  • Opt-out, not a default flip: the always-on floor keeps its zero-config value; the fidelity argument lives in design §7a.
  • initialState vocabulary: the flag rides topicOverrides (F14 keying) and mirrors the L3 initialState hook by name; resolved onto Channel.initialState (toClient records only).
  • Handler wins, loudly: an L3 initialState handler on a flagged channel still runs; the compose root warn-logs the contradiction and re-checks after POST /v1/specs/refresh.
  • Misconfiguration is loud: four spec-load warnings — override-dangling-key, initial-state-on-from-client, initial-state-non-boolean, initial-state-cross-service. The cross-service warning names the true registry.match winner: a same-address fromClient record can win, in which case the floor never runs there and every initialState declaration is dead — the warning says which case applies.
  • Observability: GET /v1/topics carries initialState: false only when suppressed (survives ?schema=false); the CLI topics views mark [no initial state].
  • Recorded semantics: retained residue on a flagged channel survives reset (contracts §2/§5 caveats + test); the flag is boot-time-only; the F21 cache-key invariant is commented at the cache site.

Doc system

R-040 tested (7 arrow-tagged test files), D-025 appended, contracts §1/§2/§5/§6 + design §7a amended, wiring guide §7 added, intake item resolved and archived. A two-axis review pass (standards + spec-vs-intake) is folded in: the cross-service warning winner fix and the toClient-scoping doc sweep (D-025/R-040 statements, model comment, plan Deviations) landed as the head commit.

Testing

Full gate set at head: check-docs, lint, typecheck all exit 0; bun test 454 pass / 0 fail (exit 0). New coverage: registry resolution + all four warnings (incl. dual-direction, same-service-disagreement, and fromClient-match-winner cases), engine gate on all legs, handler-wins, compose contradiction warn-log incl. refresh re-check, /v1/topics field presence/absence on the wire, retained-residue-across-reset, doctor tolerance.

nzneit added 17 commits August 1, 2026 19:26
…nnels

Design intake for suppressing the L1 floor on channels with no initial
state (error/notification topics), where a synthetic on-subscribe draw
can corrupt a stateful client. Resolved via design dialog:
topicOverrides.initialState:false, handler-wins-with-warning, four
spec-load warnings; allocates D-025/R-040 with the implementation PR.
…e topics views; pin residue + doctor tolerance (R-040)
…tatus + guide (R-040)

- Resolve topicOverrides.initialState onto toClient Channel records
  only; a fromClient row can no longer show initialState:false, which
  previously contradicted the initial-state-on-from-client warning.
- Same scope narrowing in mergeRegistries' cross-service check.
- Pin the new behavior with a registry test on a dual-direction
  address.
- contracts.md §1: note the toClient-only scope in the field comment.
- AGENTS.md: refresh the Status & next count (38 of 40) and mention
  the R-040/D-025 initial-state opt-out.
- wiring-your-service.md §7: add the EQ5 breadcrumb bullet the intake
  required.
@nzneit
nzneit merged commit 255aa65 into main Aug 2, 2026
1 check passed
@nzneit
nzneit deleted the initial-state-optout branch August 2, 2026 22:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant