/** One surface's declared-vs-exercised element coverage. */ export interface SurfaceReport { /** The surface name, e.g. "operations". */ readonly surface: string; /** Declared element ids (the denominator), sorted. */ readonly declared: readonly string[]; /** Element ids a test run exercised (declared ∪ unexpected), sorted. */ readonly exercised: readonly string[]; /** Declared but never exercised — the gap the gate fails on, sorted. */ readonly missing: readonly string[]; /** Exercised but not declared — a hit on an element outside the derived surface * (usually an internal/system element or a stale declaration). Informational only: * the gate does NOT fail on these. Sorted. */ readonly unexpected: readonly string[]; /** Declared elements that were exercised **via a mock at least once** (epic #296, S4). * Recorded additively: an id enters this set the first time it is exercised via a mock * (`record(..., true)`) and stays — a *later* real dispatch of the same element does NOT * remove it. So for a mixed mock+real element this means "mock-satisfied at least once", * not "exclusively via mock". A mocked element still counts as exercised — so it is NOT a * gap and never fails `assertFullCoverage` — but it is surfaced here so a reader can see the * coverage was satisfied (at least partly) by a mock rather than solely by driving the real * handler. Always a subset of `exercised`, sorted. Empty when nothing on this surface was * mock-satisfied. */ readonly mocked: readonly string[]; /** True when nothing declared is missing (`missing` is empty). */ readonly complete: boolean; } /** A whole-app coverage report across every declared surface. */ export interface CoverageReport { /** Per-surface reports, in the order surfaces were declared. */ readonly surfaces: readonly SurfaceReport[]; /** True when every declared surface is complete. */ readonly complete: boolean; } /** Options for {@link SurfaceCoverage.assertFullCoverage}. */ export interface AssertFullCoverageOptions { /** Restrict the gate to these surfaces (default: all declared surfaces). Naming an * undeclared surface is a test bug and throws. */ readonly surfaces?: readonly string[]; } /** * Tracks declared-vs-exercised coverage across an app's surfaces. Construct with an * initial set of declared surfaces (or add them later with {@link declareSurface}), * {@link record} each element as it is exercised, then {@link report} or * {@link assertFullCoverage}. */ export declare class SurfaceCoverage { #private; /** @param declared surface name → its declared element ids. */ constructor(declared?: Readonly>>); /** * Declare (or extend) a surface's element set. Idempotent: re-declaring a surface * unions the new ids in and never drops already-recorded exercises. Also registers the * surface so it appears in {@link report} / {@link assertFullCoverage} even with zero hits. */ declareSurface(surface: string, ids: Iterable): this; /** The declared surfaces, in declaration order. */ surfaces(): string[]; /** Mark `id` on `surface` as exercised. A hit on an undeclared surface still records * (surfacing later as `unexpected`), so instrumentation can run before a surface is * declared without losing data. Pass `mocked: true` when the element was exercised via a * mock (epic #296, S4): it still counts as exercised (so it is not a gap), and is * additionally flagged in {@link SurfaceReport.mocked} so the mock is visible, not hidden. */ record(surface: string, id: string, mocked?: boolean): void; /** Build a full coverage {@link CoverageReport}. */ report(): CoverageReport; /** * Throw if any gated surface has un-exercised declared elements. The error message * lists each incomplete surface with its missing element ids — the actionable "you * forgot to test these" gate. Passes silently when coverage is complete. */ assertFullCoverage(opts?: AssertFullCoverageOptions): void; }