/** * The availability producer the dashboard snapshot was missing. * * `dashboard-snapshot.ts` has accepted a `DashboardAvailabilityPort` since the SPA landed and * renders both panels, but nothing constructed one from live state, so Quota headroom and * Cooldowns were always empty. This module is that producer: it walks breaker cell state, * configured/learned limits, target-fact cooling conditions and the local ledger IN MEMORY and * emits contract rows. It performs no provider egress, no probes, and no disk reads — everything * it touches is already resident — and it never throws: a failing dependency yields empty panels * rather than failing a dashboard read. * * Rows are NOT truncated here on purpose: `availabilityRows()` in dashboard-snapshot.ts already * caps both panels at DASHBOARD_MAX_DIMENSION_ROWS and marks the cut PARTIAL in panel coverage. * Truncating here first would silently drop rows AND lose that partial flag, so the one bound * lives where the flag can be raised. */ import { type CooldownRowV1, type QuotaRowV1 } from "./dashboard-contract.js"; import type { CircuitBreaker } from "./circuit-breaker.js"; import type { AccountingStore } from "./accounting-store.js"; import { type Config } from "./config.js"; import { factsFor } from "./target-facts.js"; /** * Dependencies, all optional except the config: quotas come from whatever evidence exists (the * bare in-memory proxy has a breaker but no store, so localUsed stays null there), and cooldowns * degrade to whichever sources were supplied. */ export interface AvailabilityProducerOptions { readonly breaker?: CircuitBreaker; readonly config: Config; /** The production store exposes `usedInWindow`; anything narrower still satisfies this seam. */ readonly accounting?: Pick | null; /** Injected for deterministic tests; defaults to Date.now(). */ readonly now?: () => number; /** * The facts read seam; defaults to `factsFor`. Covers BOTH halves of the snapshot (quota resets * and the cooldown panel) — a seam only one consumer honours implies coverage it does not have. * Injected by tests to exercise the never-throws guarantee against a throwing reader; the * production default never throws. */ readonly readFacts?: typeof factsFor; } /** Shape-compatible with `DashboardAvailabilityPort`; typed locally so server.ts stays decoupled. */ export interface AvailabilitySnapshot { snapshot(): { quotas: QuotaRowV1[]; cooldowns: CooldownRowV1[]; }; } /** * Build the port handed to `createDashboardSnapshotReadPort`. One instance per proxy; each * `snapshot()` call re-reads live state, so restart-clearable breaker data recovers on its own. */ export declare function createAvailabilityProducer(options: AvailabilityProducerOptions): AvailabilitySnapshot;