/** * The key-point trigger registry (DES-TRIGGER-REGISTRY-001, TR-W5a): the runtime. * * ``` * daemon fan-in ──offer() O(1)──▶ ring[512] ─┐ * watchdog onFrame ──offerWatchdog() O(1)──▶ ├─▶ router ─▶ deterministic lane ─▶ emitter ─▶ bus ─▶ relay ─▶ /ws * bus (pulled, only types an entry wants) ───┘ * ``` * * - OFF THE HOT PATH (G3). `offer` is synchronous, allocation-light, never awaited and never throws; * an input no enabled entry listens for is dropped by one `Set.has`. * - ADVISORY BY CONSTRUCTION (G6). The registry is built with no gate, reassign or policy * dependency (`tests/watch-no-authority.test.ts` fails the build if `src/watch/**` names one). It * emits findings, flags and proposals; it never adds a needs-you row. * - ONE RECORD (§4.8). The bus. The feed is hydrated from it once at arm; each live run's persisted * events (and its wanted bus rows) are replayed through the entries at boot; every key is built * from producer-assigned identity, so a replay resolves to the rows already there. * - NO BUS, NO WATCHING (§6). Without an engine bus the registry does not arm, and health says why. */ import type { RecordedEvent, WatchCoverage, WatchEntry, WatchEntrySource, WatchFeedResponse, WatchFinding, WatchHealth, WatchKind, WatchSettings } from 'wicked-crew-api-types'; import type { CoreEvent } from '../core/types.js'; import type { DiscoverySnapshot, WatchCheck } from './types.js'; /** crew#828: the one coverage line for an ended run that recorded no events (pre-registry, or ungoverned). */ export declare const NO_EVIDENCE_REASON = "this run recorded no governance evidence (it ran before the checks existed, or ungoverned)"; /** What the route read about a run for its coverage (crew#828). */ export interface WatchRunFacts { /** The run is completed, failed or cancelled. */ ended: boolean; /** How many events the run recorded; `null` when the engine cannot say. */ events: number | null; } export interface WatchRegistryOptions { /** * TR-W6: the daemon's steering rules, read for `warned_rule` and cached for {@link RULES_SNAPSHOT_TTL_MS}. * Absent = checks see no `ctx.rules` (coverage says the store is not readable once a rule fires). */ rules?: () => Promise>; /** Test seam: the per-ask deadline on that read (default {@link RULES_READ_DEADLINE_MS}). */ rulesDeadlineMs?: number; /** * WT-W4: the project view the discovery entries count over (`src/api/discovery-source.ts`), read * per project on a cadence with a deadline; an ask past the deadline is answered from the last * view when there is one. Absent = checks see no `ctx.discovery` (their coverage says so). */ discovery?: (projectId: string) => Promise; /** Test seam: the per-ask deadline on that read (default {@link DISCOVERY_READ_DEADLINE_MS}). */ discoveryDeadlineMs?: number; /** The bus the daemon handed its engine; `undefined` = no bus, no watching. */ dbPath: string | undefined; entriesDir?: string; checks?: ReadonlyMap; /** The `watch` key of crew's settings (the operator's on/off and thresholds). */ settings: () => Promise; projectOf: (runId: string) => string | undefined; /** Runs live at boot (their persisted events are replayed, §4.8 step 2). */ liveRuns?: () => Promise; /** A run's persisted events (`Core.runEvents`); `null` = this engine cannot say. */ runEvents?: (runId: string) => Promise; /** Where `watchEvent` frames go (the relay); omitted = no relay. */ broadcast?: (frame: CoreEvent) => void; auditEmitFailed?: (detail: Record) => void; submitProposal?: (finding: WatchFinding) => Promise; log?: (msg: string) => void; now?: () => number; sleep?: (ms: number) => Promise; /** Emitter flush cadence (ms); 0 = flush only on demand (tests). */ flushMs?: number; /** Internal tick cadence (ms) for `registry-lagging`; 0 = no timer (tests tick by hand). */ tickMs?: number; /** Bus poll cadence for the relay and the pull (ms). */ pollIntervalMs?: number; ringCapacity?: number; /** Per-check budget and timeout (ms). */ checkBudgetMs?: number; checkTimeoutMs?: number; } export type DismissResult = 'dismissed' | 'not_found' | 'already_cleared' | 'emit_failed'; /** TR-W6: how long one `listConformanceRules` read serves the warned-rule check. */ export declare const RULES_SNAPSHOT_TTL_MS = 30000; /** TR-W6: how long a check waits on that read — well below the deterministic lane's 1 s timeout. */ export declare const RULES_READ_DEADLINE_MS = 400; /** WT-W4: how long one discovery view serves a project's checks. */ export declare const DISCOVERY_SNAPSHOT_TTL_MS = 30000; /** WT-W4: how long a check waits on that read — below the deterministic lane's 1 s timeout; past it the last view answers. */ export declare const DISCOVERY_READ_DEADLINE_MS = 600; export declare class WatchRegistry { private readonly opts; private armedFlag; private reasonText; private accepting; private live; private readonly checks; private shipped; private refused; private overrideProblems; private effective; private settingsNow; private router; private readonly ring; private readonly lane; private emitter; private relay; private pull; private tickTimer; private draining; private drainScheduled; private shedTickQueued; private dbPath; private readonly runStates; /** Live runs whose persisted events could not be read at boot (their coverage says so). */ private readonly gapRuns; /** The live runs could not even be listed at boot: every unseen run's coverage says so. */ private listGap; /** While the boot replay runs, live bus rows wait here (the pull is armed BEFORE the replay). */ private busHold; private readonly now; private readonly sourceState; constructor(opts: WatchRegistryOptions); get armed(): boolean; /** Arm: load entries, hydrate the feed from the bus, replay live runs, then go live. Never throws. */ arm(): Promise; private armBusPull; /** §4.8 step 2: every run live at boot is re-read from its own record and evaluated. */ private replay; /** THE HOT PATH (daemon fan-in): synchronous, O(1), never throws, never awaited. */ offer(event: CoreEvent): void; /** The watchdog's frames (the `onFrame` tee): same contract as {@link offer}. */ offerWatchdog(frame: { type: string; session?: string; } & Record): void; private offerInternal; private schedule; private drain; private stateOf; /** * TR-W6: one store read per TTL, shared by every check that asks in the window — with a DEADLINE * below the deterministic lane's timeout (codex r1), see {@link BoundedRead}. Past the deadline the * ask is refused: the check keeps the frame and classifies it on a later one. */ private rulesRead; private readRules; /** WT-W4: one bounded read per project; an ask past its deadline is answered from the last view (advisory data). */ private readonly discoveryReads; private readDiscovery; private ctx; /** Route one input through every matching entry and hand the outputs to the emitter. */ private process; /** Drain the ring and flush the emitter (tests, and shutdown). */ flush(): Promise; /** Stop taking inputs, finish what was accepted, then close the emitter and the taps. */ stop(): Promise; /** Tick the internal clock by hand (tests; the timer does this every 30 s). */ tick(): void; /** Apply the operator's `watch` settings: the effective entries and the router are rebuilt. */ applySettings(watch: WatchSettings | undefined): void; /** The 400 text for a bad `watch` patch, or `null`. */ validateSettingsPatch(patch: unknown): string | null; /** Merge a validated patch into the current `watch` settings, stamping who changed what and when. */ mergeSettings(current: WatchSettings | undefined, patch: WatchSettings, actorId: string, at: number): WatchSettings; health(): WatchHealth; /** `GET /watch/entries`: the effective entries, each threshold in plain words. */ entries(): WatchEntry[]; /** * `GET /watch`: the feed, newest first; with `run`, the run's coverage too. `runFacts` (crew#828): * what the route read about the run — whether it has ENDED, and how many events it recorded * (`null` = unknown) — so an ended run's coverage never reads "not yet". */ feed(q: { project?: string; kind?: WatchKind; run?: string; since?: number; limit?: number; runFacts?: WatchRunFacts | null; }): WatchFeedResponse; /** crew#828: the run ENDED having recorded no events at all, and the registry saw nothing of it. */ private noEvidence; /** G7: per run, which entries checked and which did not (and why). Run-less entries have none. */ coverage(runId: string, facts?: WatchRunFacts | null): WatchCoverage[]; /** "Seen, not a problem": publishes `cleared{reason:"dismissed"}` for the row. */ dismiss(watchId: string, actorId: string): Promise; /** The sources an entry can name (for the routes' validation and the docs). */ static readonly SOURCES: readonly WatchEntrySource[]; } //# sourceMappingURL=registry.d.ts.map