Skip to main content

Module reactor

Module reactor 

Source
Expand description

The reactive halves — the engine-generic reactor (ADR-019 §5, substrate.md §the reactive halves, POC-R’s validated composition).

Per record/mutation write, after the durable commit, the writing side announces its effects independently and fail-soft:

  1. Publish → the durable change feed (EVENTS_STREAM, keyed by repo id) — per-consumer durable cursors, monotone saves, replay from head; per-seq idempotency is the consumer’s rule (keyed publishes are carried metadata, not partitioning/dedup — the alkstore streams contract).
  2. Notify → the wake hint (notify/listen on WAKE_CHANNEL) — the invalidation trigger for every cached provider. Publish precedes notify (the durable carrier before the latency hint).
  3. Enqueue → the maintenance queue (MAINTENANCE_QUEUE) — the housekeeping job riding the scheduler chain. Wave 6 landed the enqueue producer side only (the recorded interpretation, gate-confirmed); the consumer side — the chain (schedule → queue → worker claim → leader TTL lock → sweep dispatch) and the liveness sources — lives in crate::maintenance and crate::liveness.

Every leg is fail-soft: its loss is exactly what the reconcile sweep exists to close — Reactor::reconcile re-reads rows_since(applied_watermark) → snapshot install → watermark advance, idempotent by construction (pure reads, monotone watermark), callable on demand and driven by the maintenance chain’s scheduler tick. No cross-store transaction machinery exists anywhere: alkstore’s TxHandle carries no consumer SQL, so an announce is always post-commit.

§The sqlite/postgres asymmetry (designed-in, ADR-019 §5)

  • sqlite: the co-tenant file is itself the invalidation bus — alkstore’s watcher data_version poll fans a wake to listen receivers on any commit to the file, including alkgit’s own registry writes on their own connection, including cross-process (~3.2 ms measured, POC-R). A lost hint cannot exist while any write lands; the reconcile sweep is a correctness backstop, not a latency bound. The post-commit notify is redundant but kept — for semantics and for postgres.
  • postgres: LISTEN/NOTIFY is load-bearing — no file-level bump exists. A lost/failed notify leaves caches stale until the reconcile tick: the tick’s cadence is the real staleness bound on postgres. (The live-pg asymmetry probe rides substrate/w6-registry-postgres’s tests.)

§The construction wiring

Reactor is constructed from the assembly’s engine handle (Arc<dyn alkstore::Store>) + the registry write side + the cached provider (CachedRegistryProvider) — the per-piece constructor the engine-twin adapter constructors wire (and the wave-8 single composition entry will unify; the recorded interpretation, flagged for the gate). Constructing the struct is infallible — every consumed surface is a fallible call at use time; the adapter-twin constructors own the loud-failure assembly posture (OpenError).

§Names pinned here (the OQ-03 substrate-side inventory for this

wave’s members)

WAKE_CHANNEL, EVENTS_STREAM, MAINTENANCE_QUEUE, MAINTENANCE_LOCK, RegistryEvent (the change-feed payload: Put/Mutation/Removed — Mutation is the per-push marker’s kind), MaintenanceJob (the maintenance-queue payload vocabulary), AnnounceReport, AppliedWatermark, Reactor, and the announced writing surface (AnnouncingRegistry — the durable write side + the reactor’s post-commit announce, the wrapper the engine-twin assembly constructors compose).

Structs§

AnnounceReport
The announce’s per-leg report — fail-soft outcomes as observation data, never an error: every leg’s loss is the reconcile sweep’s closure, so a suppressed announce carries no error path.
AnnouncingRegistry
The announced write side — the reactive composition’s writing surface: the durable registry write side folded with the reactor, so every mutation’s post-commit announce (Reactor::announce, fail-soft each) fires right after its durable commit. This is the wrapper the engine-twin assembly constructors compose — the pair’s durable contract below is unchanged (announce is never the pair’s; the wrapper is the caller, and the announce’s machinery is the reactor’s).
AppliedWatermark
The consumer-side high-water mark — the maximum sequence this composition has applied (stream events or a reconcile sweep). Monotone: per-repo keys reorder nothing (the feed is global FIFO by offset), but a reconcile may apply a sequence a live event never carried; a watermark only advances, so the composition converges to the durable side’s own truth.
Reactor
The reactor — the composition’s wired reactive halves, constructed from the substrate engine handle + the registry write side + the cached provider (the assembly-level pieces; the wave-8 composition entry unifies the whole backend’s construction).

Enums§

MaintenanceJob
The maintenance-queue payload vocabulary — what the enqueue leg lands and what the wave-7 worker dispatches on; additions extend the set.
RegistryEvent
The registry mutation event — the durable change feed’s payload. Every variant carries the mutation’s sequence number: the consumer’s per-seq idempotency key and the reconcile watermark’s currency. The Mutation variant is the per-push mutation-marker event’s kind (ADR-019 §7 — pushes do not modify RepoRecord; the marker write’s announce carries the bare mutation).

Constants§

EVENTS_STREAM
The durable change feed — the record/mutation event log. Keyed publishes carry the repo id as metadata (per-seq idempotency, not the key, is the consumer’s dedup). The feed is the notify leg’s durable carrier: a wake is latency, an event is correctness. Contract stamp: ADR-019 §5 (the durable event leg).
MAINTENANCE_LOCK
The named TTL lock the sweep dispatch takes for cross-process GC exclusion (a locked-out sweep is a skip + short retry, a value not an error — the chain’s consumer side pins the usage, wave 7; ADR-019 §6).
MAINTENANCE_QUEUE
The maintenance queue — the enqueue leg’s target and (from wave 7) the chain the scheduler fires and the maintenance worker claims from. Contract stamp: ADR-019 §5 (the maintenance enqueue leg’s target; §6 — the chain consumes it).
WAKE_CHANNEL
The wake channel — the notify/listen channel the announce’s notify leg signals and the wake runner listens on. Wakes are opaque best-effort hints (coalesced, replay-free, possibly repeated); consumers re-read — the wake receiver’s idempotency obligation is the provider’s whole-table refresh (a swap, delta-free). Contract stamp: ADR-019 §5 (the notify wake leg).