/** * @module audit * @category Internal * * Operator-driven store audit (#723). * * Walks the connected store and yields per-category {@link AuditFinding}s. * Each category answers a different "what should I do with this store?" * question and pairs with a remediation: * * - `schema` → fix the data model (poison events, unknown names) * - `close-candidate` → `app.close([...])` * - `restart-candidate` → `app.close([{stream, restart:true}, …])` * - `deprecated-load` → `app.close([...])` on the heaviest carriers * - `reaction-health` → `app.unblock(...)` / `app.reset(...)` * - `snapshot-drift` → manual `load({snap:true})` or wait for policy * - `routing-health` → restart-with-new-config to re-lane * - `correlation-gaps` → fix upstream correlator misconfig * - `clock-anomalies` → infra remediation (clock skew) * * ## Single-scan multiplex (efficiency contract) * * Earlier draft had each category run its own `store.query(...)`, * which meant N requested categories → N table walks. Bad for large * stores. Refactored to a pass-based design: each category is a * factory that returns an {@link AuditPass} with optional per-row * callbacks (`on_event` / `on_stream` / `on_stat`) and a `finalize` hook * for any second-pass work. The dispatcher determines the UNION of * required data sources, runs each *once*, and broadcasts each row * to all interested passes. Worst case: three scans total (events, * streams, stats) regardless of how many categories the operator * requested. Most categories also share state — close-candidate and * restart-candidate both consume the same `on_stat` stream; schema, * correlation-gaps, and clock-anomalies all hang off the same * `on_event` broadcast. * * Categories that need follow-up work (snapshot-drift's per-stream * snapshot lookup, correlation-gaps' orphan-id check after collecting * ids) do that in their `finalize` hook with their own targeted store * calls — keeps the shared scan path minimal. * * Isolated from orchestration internals — `act.ts` builds the * {@link AuditDeps} bag at `.build()` time and hands it here via * a one-liner. The audit module never reaches into * `internal/{event-sourcing,drain-cycle,settle,close-cycle}.ts`; it * only reads through the deps interface and the public `Store` * surface. Same shape as `act-tck` within the workspace — a peer of * orchestration, not entangled with its private mechanics. * * @internal */ import type { AuditCategory, AuditFinding, AuditOptions, Logger, State, Store } from "../types/index.js"; /** * Snapshot of orchestrator state the audit reads. Built once at * `app.build()`; the audit treats it as immutable for the duration * of a call. The orchestrator never passes its own private maps in * directly — this bag is the abstraction boundary so a future * orchestration refactor can't accidentally entangle with audit * logic. */ export type AuditDeps = { readonly store: () => Store; readonly logger: Logger; /** event-name → state that registers it (for schema validation). */ readonly event_to_state: ReadonlyMap>; /** state-name → state (for snapshot-supported check on restart-candidate). */ readonly states: ReadonlyMap>; /** Declared drain lanes (for routing-health unknown-lane). */ readonly declared_lanes: ReadonlySet; /** * Event names that the registry has at least one reaction for — * used by routing-health to detect "registered but unrouted" * events. Normalized down from the internal `event_to_lanes` map * (which carries lane-set details audit doesn't need). */ readonly routed_events: ReadonlySet; }; /** * Top-level audit dispatcher. Single-scan multiplex: each requested * category contributes a `AuditPass`, the dispatcher determines the * union of required data sources (events / streams / stats), runs * each once, broadcasts rows, and yields per-category findings in * the order the categories were requested. * * Callers can `break` the iteration early — the underlying scan * loops have already completed by the time yield starts, so early * break only saves the iteration over already-collected findings. * (Per-row early termination during a scan isn't feasible without * coordination across passes; the audit is bounded by `options.query` * scoping rather than mid-scan cancellation.) */ export declare function audit(deps: AuditDeps, categories?: AuditCategory[], options?: AuditOptions): AsyncIterable; //# sourceMappingURL=audit.d.ts.map