/** * First-class confidence ledger (#399): how complete and trustworthy was the * capture, stated per surface — separate from whether captured styles changed. * * A green visual verdict answers "did captured computed styles change?". This * ledger answers the second question a reviewer needs: "was everything that * matters captured, and what prevented stronger confidence?" The two are * rendered as two badges and never merged into one green. * * Producers write into this ledger; they do not compete with it: * - the capture itself (`captured` entries, downgraded to `unproven-determinism` * when the run recorded no self-check/replay basis); * - the coverage registry (`excluded-with-reason` opt-outs, `unknown` for * declared-but-never-captured surfaces); * - the auth-boundary classifier (#390 — `inaccessible` walls, or * `excluded-with-reason` when acknowledged); * - the incomplete-UI classifier (#398 — `inaccessible` blocked continuations). * * Honesty rules: no coverage percentage is ever invented for surfaces that * cannot be enumerated (`basis: 'unasserted'` says so instead); bundles from * before this ledger existed degrade to `unknown` and never block * retroactively; every non-`captured` entry carries a non-empty reason. */ import { type CoverageLedger } from './coverage.js'; import { CONFIDENCE_LEDGER } from './map-store.js'; /** Bundled next to the maps, like the coverage ledger, so confidence travels with the capture. */ export { CONFIDENCE_LEDGER }; /** Per-surface trust statuses — the vocabulary of the ledger (#399). */ export type ConfidenceStatus = 'captured' | 'excluded-with-reason' | 'inaccessible' | 'unknown' | 'unproven-determinism'; /** Which subsystem asserted a status — named producers, not competing formats. */ export type ConfidenceProducer = 'capture' | 'coverage' | 'determinism' | 'auth-boundary' | 'incomplete-ui'; export type ConfidenceEntry = { /** Captured surface key, declared registry key, or redacted auth observation key. */ surface: string; status: ConfidenceStatus; producer: ConfidenceProducer; /** Present and non-empty on every non-`captured` status. */ reason?: string; }; export type ConfidenceLedgerFile = { version: 1; /** * Whether a declared `expected` registry backed the captured set. `unasserted` * means the surface universe cannot be enumerated, so completeness can never * be claimed — and no percentage is invented for it. */ basis: 'asserted' | 'unasserted'; entries: ConfidenceEntry[]; }; /** The run-level completeness badge, distinct from the visual verdict. */ export type ConfidenceCompleteness = 'complete' | 'limited' | 'unasserted' | 'unknown'; export type ConfidenceSummary = { counts: Record; completeness: ConfidenceCompleteness; }; /** Auth-boundary observations already resolved by {@link resolveCrawlConfidence}. */ export type ConfidenceAuthInput = { acknowledged: Array<{ key: string; reason: string; }>; unacknowledged: Array<{ key: string; }>; }; /** Blocked-continuation residue from the incomplete-UI classifier (#398). */ export type ConfidenceIncompleteUiInput = { surface: string; /** Deterministic classifier reasons (e.g. `form-present`) — never field values. */ reasons: string[]; }; /** * Build the ledger from the producers' signals. Pure and deterministic: entries * are keyed by surface (strongest status wins) and sorted by surface key. */ export declare function buildConfidenceLedger(input: { capturedKeys: Iterable; /** The bundle's coverage ledger, or null when it carries none. */ coverage: CoverageLedger | null; /** Resolved auth-boundary walls (#390). */ auth?: ConfidenceAuthInput; /** Blocked-continuation residue (#398). */ incompleteUi?: ConfidenceIncompleteUiInput[]; /** Discovered crawl surfaces that did not produce a complete map sweep. */ captureGaps?: Array<{ surface: string; reason: string; }>; }): ConfidenceLedgerFile; /** * Collapse a ledger to the completeness badge + per-status counts. `null` * (a bundle from before the ledger existed) degrades to `unknown` — it never * blocks retroactively. No percentage is ever computed: `unasserted` says the * universe cannot be enumerated, and counts stay counts. */ export declare function summarizeConfidence(ledger: ConfidenceLedgerFile | null): ConfidenceSummary; /** Write the ledger into a capture bundle (next to the maps). */ export declare function writeConfidenceLedger(dir: string, ledger: ConfidenceLedgerFile): string; /** * Read a bundle's persisted ledger. Missing OR malformed → null (degrade to * `unknown`). Lenient deliberately, unlike the coverage ledger's fail-loud read: * this ledger arms no gate, so a corrupt file can only understate confidence — * it can never disarm coverage, determinism, or residue enforcement. */ export declare function readConfidenceLedger(dir: string): ConfidenceLedgerFile | null; /** * The ledger a REPORT should state for a bundle: the persisted file when a * producer wrote one (a crawl capture), merged with what the bundle's own * coverage ledger + map files prove (a spec capture — whose parallel test * runner cannot know the captured set at write time, so the report derives it). * A bundle with neither source returns null → the `unknown` badge. */ export declare function resolveBundleConfidence(dir: string): ConfidenceLedgerFile | null; /** * Lenient coverage-ledger read for ADVISORY consumers (this resolver, the * report's certification renderer): a missing or corrupt file degrades to null. * The diff CLI keeps its own fail-loud read — there, an unreadable ledger would * silently disarm the coverage/determinism/residue gates. */ export declare function readCoverageLedgerLenient(dir: string): CoverageLedger | null; /** Deduped surface keys captured in a bundle dir (`@.json[.gz]` → ``). */ export declare function bundleSurfaceKeys(dir: string, expected?: readonly string[] | null): string[];