Skip to main content
Version: Current

Behavior-contract checklist

A documented runtime guarantee is a lie until a test fails when it stops holding. The with_snaps regression (#1024) shipped a doc/intent that had quietly diverged from the code because nothing executable pinned the claim. This page is the antidote: every load-bearing behavioral claim Act makes in its docs and port doc-comments, mapped to the test that enforces it.

The rule that follows from it lives in the pre-handoff workflow: a doc claim about runtime behavior ships with its test. When you add or change a claim here, add or update the row.

Scope is deliberately narrow β€” load-bearing guarantees a caller or adapter author would rely on, not every sentence in the docs. Adapter-level claims are backed in the TCK (libs/act-tck/src/store-tck.ts) so they run against InMemory, Postgres, and SQLite at once; orchestrator and builder claims are backed by unit/integration specs under libs/act/test/.

Cache and snapshots​

ClaimSourceBacking test
seed() is the schema maintenance story: additive, idempotent, lossless on any prior released shape, and safe to run on every boot from every worker (advisory-locked on Postgres for concurrent cold boots)writing-a-store.md Β§ The store schema is the framework's job; extension-points.mdact-pg + act-sqlite seed-upgrade.spec.ts β†’ "upgrades the oldest supported shape losslessly and idempotently", "serializes concurrent cold boots on an empty schema" (#1140)
On Postgres, streams.retry is int (widened from smallint via the seed ladder), so a persistently-failing blockOnError: false stream whose retry counter climbs unbounded never overflows claim()'s retry + 1 update β€” matching the unbounded SQLite/InMemory adapterswriting-a-store.md Β§ The store schema is the framework's jobact-pg retry-overflow.spec.ts β†’ "claims a stream whose retry sits at the old smallint ceiling"; seed-upgrade.spec.ts β†’ "upgrades the oldest supported shape…" (asserts retry migrated to integer) (#1190)
with_snaps: true resumes from the latest snapshot per stream; an explicit after overrides the floor; a stream with no snapshot returns full historycache-and-snapshots.md, Store.query docstore-tck.ts β†’ "with_snaps resumes from the latest snapshot per stream"
Cold start absorbs the snapshot event into state and resets patches to 0 (snaps increments)cache-and-snapshots.md "How the two interact on cold start"event-sourcing.spec.ts β†’ "should load from a snapshot event on cold start"
Snapshot writes are fire-and-forget; a snap failure does not propagatecache-and-snapshots.md "Snapshot creation"event-sourcing.spec.ts β†’ "should not throw on snap error and warn with stream, reason, and hint"
A snapshot write failure never fails the action and is surfaced at warn level with the stream, reason, and full-replay hintcache-and-snapshots.md "Snapshot creation"event-sourcing.spec.ts β†’ "should complete the action and warn when the snapshot write fails"
A successful snap predicate commits a __snapshot__ eventcache-and-snapshots.mdevent-sourcing.spec.ts β†’ "should persist snapshot event on snap success"
Cache miss populates the cache; a warm hit replays nothing oldercache-and-snapshots.md "Read path"cache.spec.ts β†’ "cache miss populates cache on load"
The cache is invalidated only on ConcurrencyErrorcache-and-snapshots.md "Cache invalidation β€” narrow contract"cache.spec.ts β†’ "cache invalidated on ConcurrencyError"
Invariant / validation failures (no commit) leave the warm cache untouchedcache-and-snapshots.md "Anything else … leaves the cache untouched"cache.spec.ts β†’ "invariant failure leaves the warm cache untouched", "validation failure leaves the warm cache untouched" (gap filled β€” #1029)
A cache.set rejection is logged, not fatal to the actioncache-and-snapshots.mdcache.spec.ts β†’ "cache.set rejection is logged but does not fail the action"
Time-travel (asOf) bypasses cache read and write, and ignores snapshots after the cutoffcache-and-snapshots.md "Time-travel reads"time-travel.spec.ts β†’ "should not read from cache…", "should not write to cache…", "should not use snapshots…"

Reactions, drain, and errors​

ClaimSourceBacking test
On Postgres, event ids become visible in id order β€” the append path (commit, truncate) holds a transaction-scoped advisory lock so a concurrent cross-stream commit can never surface below an id a watermark consumer already acked pastconcurrency-model.md Β§ Commit visibility orderingact-pg commit-visibility.spec.ts β†’ "a commit waits for an in-flight append transaction to finish", "truncate seeds take the same visibility lock" (#1178)
reactingTo is auto-injected when a reaction handler omits it; an explicit value is respectedCLAUDE.md safety one-liner; state-management.mdreacting-to.spec.ts β†’ "should auto-inject reactingTo when handler omits it", "should respect explicit reactingTo when provided"
NonRetryableError forces a block on the first attempt when blockOnError is true (default)error-handling.md "Non-retryable errors"non-retryable.spec.ts β†’ "blocks on first attempt when blockOnError is true (default)"
NonRetryableError does not override blockOnError: falseerror-handling.md; CLAUDE.md safety one-linernon-retryable.spec.ts β†’ "ignores NonRetryableError when blockOnError is false"
Per-reaction backoff defers retry until the window elapses (per-worker)error-handling.md "Backoff"backoff.spec.ts β†’ "defers retry until backoff window elapses (per-worker)"
Backoff entry clears on a successful ackerror-handling.mdbackoff.spec.ts β†’ "clears backoff entry on successful ack"
Backoff still blocks when retries are exhaustederror-handling.mdbackoff.spec.ts β†’ "preserves blocking behavior when retries are exhausted"
compute_backoff_delay strategy/clamp/jitter semanticserror-handling.mdbackoff.spec.ts β†’ compute_backoff_delay unit block
Backoff's effective floor is max(configured, leaseMillis) β€” when the lease outlasts the backoff window, the held lease (not the timer) gates the next attempterror-handling.md "Backoff"; CLAUDE.md "Reaction backoff is per-worker"backoff.spec.ts β†’ "effective floor is max(configured, leaseMillis) β€” the held lease dominates a short backoff" (gap filled β€” #1065)
app.unblock resumes a blocked stream from its watermark without replaying history; app.reset rewinds to -1 and replays everything (the resume-vs-rebuild distinction)CLAUDE.md "Blocked-stream recovery"; error-handling.mdnon-retryable.spec.ts β†’ "recovers via app.unblock without replaying history"; rebuild.spec.ts β†’ "should enable replay of projection after reset" (gap filled β€” #1065)
correlate() arms the lane controllers when it subscribes new streams β€” the same contract reset/unblock honor β€” so a freshly-discovered dynamic target cannot starve on a lane whose worker disarmed before the subscription landedcorrelation-and-drain.mdcorrelate-arm.spec.ts β†’ "revives a lane that disarmed before the subscription landed"
A state projection's flush precedes its watermark ack β€” a failed flush holds the watermark and the retry re-folds to the same rows (idempotent at-least-once)projections-to-database.mdstate-projection.spec.ts β†’ "holds the watermark when flush fails and converges on retry"
A state projection evicting under maxCachedStates pressure flushes the evictee first β€” eviction never loses folded workprojections-to-database.mdstate-projection.spec.ts β†’ "flushes the evictee before dropping it under maxCachedStates pressure"
A state projection rebuild writes one row per stream per flush round, not one per eventevent-sourcing.md Β§ Projection Rebuildstate-projection.spec.ts β†’ "rebuilds in O(streams) upserts, not O(events)"
A state projection'''s first-sight load resumes from the latest snapshot floor and folds only the tailprojections-to-database.md Β§ State projectionsstate-projection.spec.ts β†’ "resumes the first-sight load from the latest snapshot"
A cache entry's state equals the fold of events at or below its event_id β€” a guardless commit that lands past the loaded frontier invalidates instead of caching a gapped foldcache-and-snapshots.mdcache-frontier.spec.ts β†’ "never leaves a stale-at-head cache entry after guardless commits"
The optimistic guard holds on warm cache hits β€” a concurrent plain action surfaces ConcurrencyError, never a silent append past unfolded eventsconcurrency-model.mdcache-frontier.spec.ts β†’ "keeps the optimistic guard on warm cache hits"
A cold load during the close guard window (tombstone committed, truncate pending) does not cache β€” leaving the entry cold keeps action()'s cold-path tombstone check live, so a subsequent action throws StreamClosedError instead of committing past the tombstoneconcurrency-model.md; close-cycle.mdevent-sourcing.spec.ts β†’ "a cold load during the guard window keeps the tombstone check live" (#1188)
A snapshot event is only persisted from a contiguous fold, and the action awaits it and caches the snap frontier before returning β€” sequential callers never see a conflict caused by the framework's own bookkeepingcache-and-snapshots.mdoptimizations.spec.ts cadence + calculator.spec.ts lifecycle (fail on regression)
Lanes drain in parallel β€” _drain_all runs every controller's drain() via Promise.all, so a stalled slow-lane handler does not block the fast laneCLAUDE.md "Lanes give intra-process responsiveness"; configuration.md Β§ Laneslanes.spec.ts β†’ "drains lanes in parallel β€” a stalled slow handler does not block the fast lane" (gap filled β€” #1065)
A defer outcome holds the triggering event pending β€” the drain does not advance the watermark and does not bump retry β€” then re-delivers once the persisted due-time passesclose-cycle.md Β§ Defer, not poll; extension-points.md Β§ deferdefer-outcome.spec.ts β†’ "holds pending until the due-time, then redelivers and acks" (#1090)
The registry is complete and frozen at act().build(): autoclose reactions are synthesized by the builder (not the orchestrator), and post-build mutation of the registry containers throwsclose-cycle.md Β§ Online close-the-booksregistry-freeze.spec.ts β†’ "freezes the registry containers at build", "synthesizes the autoclose reaction at build, not construction" (#1121)
.autocloses closes a stream when its policy matches the live head, re-evaluates the live head so a reopened stream is not closed, parks on the cooldown while after has not elapsed, closes on a reaches threshold, and defers (not closes) outside the autocloseWindowclose-policies.md; close-cycle.md Β§ Online close-the-booksautoclose-reaction.spec.ts β†’ "closes immediately on the terminal event for an is policy", "evaluates the live head β€” a reopened stream is not closed", "parks on the cooldown instead of closing while after has not elapsed", "closes on the threshold event for a reaches policy", "respects the off-hours window β€” outside it, defers instead of closing" (#1090)
The declarative .defer(when) builder step holds the reaction until its schedule is due, then runs the handler once (available on both act() and slice())state-management.md Β§ Deferred reactionsdeclarative-defer.spec.ts β†’ "literal { after } holds the reaction (handler not run, not acked)", "runs immediately once the schedule is already due", "is available on the slice() builder too" (#1091)
The .defer function form reads the triggering event's payload to choose the schedulestate-management.md Β§ Deferred reactionsdeclarative-defer.spec.ts β†’ "function form reads the payload to choose the schedule, then runs" (#1091)
Drain finalization is atomic: defer schedules ride the same Store.ack call as the acks (due-marked leases), so a failed finalize lands nothing β€” close requests are never lost, no watermark moves without its cycle's schedulesclose-cycle.md Β§ Defer, not poll; extension-points.md Β§ Store; recipes/temporal/recurring-timers Β§ Failure modesdefer-durability.spec.ts β†’ "a failed finalize lands nothing β€” close requests are never lost", "persists the defer schedule in the same store call as the acks"; TCK store-tck.ts β†’ describe("ack finalize (due-marked leases)") (#1124)
A failed finalize never stalls a deferred stream: the controller stays armed and the next drain redelivers, so the handler re-throws its DeferSignal and the retried finalize persists the scheduleclose-cycle.md Β§ Defer, not polldefer-durability.spec.ts β†’ "keeps the drain armed while finalization is unhealed" (#1124)
A malformed literal .defer(...) schedule (neither/both of after/at, or an empty duration) is rejected at build time with a ZodErrorstate-management.md Β§ Deferred reactionsdeclarative-defer.spec.ts β†’ "rejects a bad literal schedule at build time" (#1091)
Imperative throw new DeferSignal(when) resolves the schedule against the triggering event and holds the stream until the due-time, then re-delivers and acksstate-management.md Β§ The DeferSignal escape hatchpublic-defer.spec.ts β†’ "{ at: Date } holds until the due-time, then acts", "{ after } is measured from the event's created time (parks, not acked)" (#1091)

Store contract (runs on all three adapters via the TCK)​

ClaimSourceBacking test
subscribe is idempotent on repeatStore.subscribe docstore-tck.ts β†’ "subscribes new streams and is idempotent on repeat"
subscribe keeps the maximum priority when a stream is re-subscribed with a different priorityStore.subscribe priority doc-commentstore-tck.ts β†’ "keeps the maximum priority when a stream is re-subscribed" (gap filled β€” #1029)
prioritize sets priority directly, overriding subscribe's max() ruleStore.prioritize docstore-tck.ts β†’ "sets priority directly, overriding subscribe's max() rule"
unblock returns 0 when the stream is not blocked; reset/unblock return 0 for unknown/empty inputStore.unblock / Store.reset docsstore-tck.ts β†’ "returns 0 when the stream is not blocked", "returns 0 for unknown streams and empty input"
unblock clears the blocked flag and preserves the watermark; reset rewinds it to -1 (resume-vs-rebuild at the port level)Store.unblock / Store.reset docsstore-tck.ts β†’ "clears blocked flag and preserves the watermark", "rewinds a stream watermark to -1", "clears blocked status when resetting" (gap filled β€” #1065)
truncate (full target) deletes events, removes the stream entry, and seeds a snapshot or tombstoneStore.truncate docstore-tck.ts β†’ truncate describe block
A windowed truncate target (before) deletes only the prefix below the closest safe snapshot (latest __snapshot__ with created < before), keeps the snapshot + tail, seeds nothing, and leaves subscriptions untouched β€” the stream stays writable and readableStore.truncate doc; extension-points.md Β§ Store contract; writing-a-store.md Β§ Truncating streamsstore-tck.ts β†’ describe("windowed (before boundary)"): "deletes the prefix below the closest safe snapshot and keeps the snapshot + tail", "leaves subscriptions untouched, unlike a full truncate", "keeps the stream writable and readable after a prune", "mixes full and windowed targets in one call" (#1011)
The max_id cap on a windowed target is honored β€” the boundary never rises past a lagging consumer's watermark, so a lagging reaction degrades the prune, never loses dataStore.truncate doc; close-cycle.md Β§ Windowed closestore-tck.ts β†’ "honors the max_id cap β€” boundary never rises past a lagging consumer"; close-windowed.spec.ts β†’ "caps the boundary at a lagging consumer's watermark" (#1011)
A windowed target with no qualifying snapshot is a no-op: events untouched, stream absent from the truncate result, reported in CloseResult.skipped by the orchestratorStore.truncate doc; close-cycle.md Β§ Skipped semanticsstore-tck.ts β†’ "no-ops when no snapshot qualifies β€” stream absent from the result, events untouched"; close-windowed.spec.ts β†’ "skips streams with no qualifying snapshot" (#1011)
forget_pii wipes PII for every event and is idempotent (second call returns 0; no-PII stream returns 0)Store.forget_pii docstore-tck.ts β†’ "wipes pii for every event on the stream via forget_pii", "is idempotent β€” second forget_pii returns 0, no error", "forget_pii on a stream with no pii events returns 0"
query_streams reports maxEventId tracking the highest committed idStore.query_streams docstore-tck.ts β†’ "maxEventId tracks the highest committed id"
claim skips a stream until its deferred_at passes, then makes it claimable again; a defer never bumps retry; reset clears a pending defer; a filter-form defer counts the streams it matchedStore.defer doc; extension-points.md Β§ deferstore-tck.ts β†’ defer describe block: "hides a stream from claim until its deferred_at passes", "makes a stream claimable once the deferred_at is in the past", "does not bump retry while a stream is deferred", "reset clears a pending defer", "defers streams matching a filter and counts matches" (#1090)
Stream filters guarantee a portable grammar β€” ^ / $ anchors, ., .*, literal characters (including literal _ / %) β€” matching identically on every adapter; a richer pattern either matches with full regex semantics or throws ValidationError, never a silent approximationQueryStreams.stream / StreamFilter / Query.stream docs; extension-points.md Β§ Stream filtersstore-tck.ts β†’ "stream filter grammar" describe block: "portable subset: anchors, ., and .* match identically", "literal _ and % in patterns are not wildcards", "portable subset applies to stream-position filters", "non-portable patterns match with full regex semantics or throw", "bulk stream ops reject non-portable filters instead of mis-matching" (#1114)
claim treats a subscription's source as an exact stream name β€” a source s1 never matches a sibling stream s12, and an exact-source subscription receives exactly its stream's events (patterns belong to the StreamFilter surfaces, never to claim)Store.claim / Store.subscribe docs; Resolved.source docstore-tck.ts β†’ describe("claim source matching"): "treats source as an exact stream name β€” no substring or pattern overmatch", "receives exactly its source stream's events" (#1182 β€” the overmatch case failed red on InMemory's unanchored-RegExp and SQLite's contains-LIKE probes before the fix)
A lease timeout counts against the retry budget β€” reclaiming an expired lease increments retry no matter which worker reclaims it, and only ack resets the counterconcurrency-model.md Β§ Timeout; Store.claim docstore-tck.ts β†’ "counts a timed-out lease reclaimed by another worker against the retry budget; ack resets it" (#1183 β€” the doc previously claimed the opposite; the code was right)
An unexpired lease is invisible to competing claimers; an expired lease is handed to exactly one of them, with the shared retry counter intactconcurrency-model.md Β§ Timeout / lease lifecyclestore-tck.ts β†’ concurrency (capability): "does not hand an unexpired lease to a competing claimer", "hands an expired lease to exactly one competing claimer, with retry accounting shared across workers" (#1184)
notify is self-filtering β€” an instance never receives its own commits, only a sibling instance's writing to the same backing storeStore.notify doc ("implementations must skip their own commits")store-tck.ts β†’ notify (capability): "does not deliver an instance's own commits (self-filtering)" (#1184 β€” promoted from adapter-local suites to the TCK so third-party stores can't badge conformance while echoing their own commits)
notify delivers one notification per commit transaction, carrying the full ordered event batchStore.notify doc; cross-process-reactions.mdstore-tck.ts β†’ notify (capability): "delivers one notification per commit transaction carrying the full event batch" (#1184)

PostgresStore notify (adapter-specific β€” outside the TCK)​

The portable notify contract (cross-instance delivery, self-filtering, batch-per-commit) lives in the TCK's notify capability suite as of #1184. What stays here is PostgreSQL plumbing the TCK can't express portably β€” the LISTEN reconnect discipline and the 8000-byte NOTIFY payload cap β€” pinned in libs/act-pg/test/.

ClaimSourceBacking test
notify is self-filtered per instance β€” a commit wakes other instances' listeners, never its own (the LISTEN handler skips payloads where by === this._by)cross-process-reactions.md Β§ Self-filternotify.contract.spec.ts (act-pg) β†’ "notify is self-filtered per instance β€” a commit wakes the other instance, never its own" (#1120)
An oversize NOTIFY payload (β‰₯ 8000 bytes) skips the NOTIFY instead of aborting the commit β€” the commit succeeds and delivery falls back to the poll path, preserving at-least-oncecross-process-reactions.md Β§ Payload capnotify.contract.spec.ts (act-pg) β†’ "oversize notify payload skips the NOTIFY β€” the commit succeeds and events stay discoverable via the poll path" (gap exposed a real bug, fixed β€” #1120)
The dedicated LISTEN client carries an error listener, so a connection loss cannot crash the process; on error it tears the dead client down and re-LISTENs on a fresh one with capped exponential backoff, degrading to the poll path in betweencross-process-reactions.md Β§ Connection loss β€” the LISTEN client self-healsnotify.resilience.spec.ts (act-pg) β†’ "attaches an error listener…", "self-heals: on client error it tears down the dead client and re-LISTENs on a fresh one", "grows the backoff on repeated failures and resets it after a healthy reconnect" (#1189)
A pending reconnect is cancelled by disposal (or a re-subscribe) β€” no reconnect fires after teardowncross-process-reactions.md Β§ Connection loss β€” the LISTEN client self-healsnotify.resilience.spec.ts (act-pg) β†’ "dispose during a pending reconnect cancels it β€” no client is checked out after teardown" (#1189)

Orchestrator and builders​

ClaimSourceBacking test
app.reset() arms the orchestrator's drain flag, so a settled app still replays (store().reset() alone does not)CLAUDE.md safety one-liner; event-sourcing.mdrebuild.spec.ts β†’ "should replay events when drain runs after reset on a settled app"
reset resets watermarks to -1 and unblocks blocked streamsStore.reset docrebuild.spec.ts β†’ "should reset subscribed stream watermarks to -1", "should unblock blocked streams after reset"
A static .emit() of a deprecated event version throws at buildevent-schema-evolution.md; CLAUDE.md safety one-linerdeprecation.spec.ts β†’ "throws when an action statically emits a deprecated event"
Single-key records (.on, state(...)) throw on zero or multiple keysCLAUDE.md safety one-liner; state-management.mdstate-builder.spec.ts β†’ "should throw when .on() receives multiple keys", "should throw when record has more than one key", "should throw when record has zero keys"
Same-name state partials sharing an event must reference the same Zod schema instance; mismatched references throwCLAUDE.md safety one-liner; state-management.mdslice.spec.ts β†’ "throws when same-name state partials use different schema references for the same event"
Scoped Acts keep per-Act store and cache isolated (no cross-talk)CLAUDE.md safety one-liner; extension-points.mdscope.spec.ts β†’ "two Acts with their own scoped ports β€” no cross-talk", "scoped cache keeps per-Act snapshots isolated"
A scoped Act's background paths β€” settle-driven correlate init, the start_correlations poll timer, and per-lane worker ticks β€” resolve store()/cache() to the scoped ports, not the singleton: static targets subscribe and drains run on the scoped storeCLAUDE.md "Per-Act scoped ports"; extension-points.md Β§ Scoped portsscope.spec.ts β†’ "settle() subscribes static targets on the scoped store, not the singleton", "start_correlations polls against the scoped store, not the singleton", "lane worker ticks drain against the scoped store, not the singleton" (#1191)
Cross-process reactions: the orchestrator auto-wires Store.notify at construction when the store supports it and reactive events exist; it does not wire when the store lacks notify or there are no reactive eventsCLAUDE.md "Cross-process reactions"; cross-process-reactions.mdnotify.spec.ts β†’ "subscribes when store has notify and reactions exist", "does not subscribe when store lacks notify", "does not subscribe when there are no reactive events" (gap filled β€” #1065)
A windowed close leaves the cache untouched and the stream live β€” no invalidation on prune, and the stream keeps accepting actionsclose-cycle.md Β§ Windowed close; IAct.close doc-commentclose-windowed.spec.ts β†’ "prunes the prefix behind the boundary snapshot and keeps the stream live", "leaves the cache untouched β€” no invalidation on prune" (#1011)
.autocloses({ keep }) requires .snap(...) earlier in the chain β€” type-gated on the ActionBuilder, with a runtime throw backstopping untyped callers β€” and rejects windows below one day and keep inside orclose-policies.md Β§ keep; AutoclosePolicy.keep doc-commentautoclose-builder.spec.ts β†’ describe(".autocloses({ keep }) β€” rolling window"): "requires .snap earlier in the chain β€” the runtime guard for untyped callers", "gates keep behind .snap at the type level", "rejects windows below one day β€” close is low-cadence housekeeping", "rejects keep inside the or block" (#1011)
A stream is never acked past an event while any reaction on it is unhandled β€” a mid-group failure holds the watermark, redelivers the whole group (already-succeeded reactions re-run, at-least-once), and counts as no progress so the retry counter marches toward blockOnErrorerror-handling.md Β§ Retry pattern; concurrency-model.md at-least-onceintra-event-ack.spec.ts β†’ "holds the watermark when a later reaction on the same event fails", "acks the group once every reaction on the event succeeds", "keeps cross-event partial progress β€” completed events ack, the failing group holds" (#1179)
A keep prune is staged only once the stream's oldest domain event ages out of the window; otherwise the reaction defers to tail.created + keep, and a terminate match takes precedence (full close) with terminate and prune staying independentclose-policies.md Β§ keep; close-cycle.md Β§ Online close-the-booksautoclose-reaction.spec.ts β†’ describe("autoclose rolling window (keep)"): "defers while the window holds, prunes once the tail ages out", "terminate and prune stay independent β€” is full-closes even with keep declared", "passes the cutoff to the archiver on a windowed close", "skips the prune when no snapshot qualifies, retrying next trigger" (#1011)

Gaps closed by #1029​

Two load-bearing claims had no executable backing before this checklist:

  • Cache narrow-invalidation, negative half. The docs guarantee that invariant / validation failures leave the warm cache untouched (only ConcurrencyError invalidates). Nothing tested the negative case β€” a regression that invalidated on every throw would have passed CI. Closed in cache.spec.ts.
  • subscribe max-priority merge. The Store.subscribe doc-comment mandates that re-subscribing a stream keeps the maximum priority so the highest-priority reaction wins. No adapter test enforced it; a last-write-wins regression on any adapter would have shipped silently. Closed in store-tck.ts (runs on InMemory, Postgres, SQLite).

No documented claim was found to be false against the code during this audit; both gaps were missing tests for behavior that already held.

Audit closed by #1065​

#1029 seeded the checklist; #1065 walked the remaining load-bearing documented runtime guarantees to exhaustion. Most already had backing tests that were simply not yet recorded here β€” the blocked-stream resume-vs-rebuild distinction (non-retryable.spec.ts, store-tck.ts, rebuild.spec.ts) and the cross-process notify auto-wiring contract (notify.spec.ts) are now mapped to their rows. Two guarantees had no executable backing and gained a focused test:

  • Backoff's effective floor. The docs guarantee the floor is max(configured, leaseMillis) because the controller holds the lease for the whole window. Every existing backoff test used leaseMillis: 1, so the lease-dominates case was untested. Closed in backoff.spec.ts (a 20ms backoff under a 500ms lease retries only after the lease expires).
  • Lane drain parallelism. lanes.spec.ts covered controller wiring, arming, and worker lifecycle but never the actual concurrency guarantee: that _drain_all's Promise.all lets the fast lane complete while a slow-lane handler is stalled. Closed with a gated-handler test.

No documented claim was found false against the code during this audit; every remaining gap was a missing test for behavior that already held.