/** * Binding a `qa-run:` receipt — a recorded native typecheck or lint run — to * the change it claims to check (T13427, design note * `t13427-qa-run-binding-design`, owner decision option 1). * * What a bound atom guarantees, exactly: * 1. **Result.** The receipt states exit code 0 and zero error diagnostics. * 2. **Freshness.** The same clock as `test-run:` ({@link reportFreshness}): * the run is not older than the change's commits, edits or deletions. * 3. **Coverage.** Every changed code path the check can read (lint: JS/TS * family sources; typecheck: TS sources — {@link qaRunChecks}) lies under * a root of a receipt of that kind; a changed path neither check reads * (a generated `.md` under `scripts/`, a `.json`) lies under a root of any * receipt, or the gate names it as needing its own evidence (T13698). * Evidence-scoped, docs ignored. In a workspace, every package * that depends on a changed package is covered by a root at or above its * directory, since a type change breaks importers. A workspace-wide change * (a path outside every package) is refused: only a whole-project run * speaks for it — unless the change is non-code only (docs, editor settings; * T13745), when no package is affected and a lint (or structural) receipt * holding the files stands without a typecheck. * 4. **Identity.** HEAD and the tool-cache tree hash are recorded by the * validator; `cleo complete` refuses the atom once the tree moves, unless * merged CI carries the gate. * * With no origin default branch to diff against (no merge base), nothing is * judged beyond the result: the receipt binds with no coverage check, as a * `test-run:` report does there. * * It does NOT prove the run happened (a receipt is a file the caller * supplies), and a scoped typecheck does not see unchanged files outside its * roots that import a changed export. Merged CI (`ci:`) or a whole-project * `tool:typecheck` speaks for the whole program. * * @task T13427 */ import type { EvidenceAtom } from '@cleocode/contracts'; /** The QA checks a receipt can record: one of each satisfies `qaPassed`. */ export declare const QA_RUN_KINDS: readonly ["typecheck", "lint"]; /** A QA check a receipt records. */ export type QaRunKind = (typeof QA_RUN_KINDS)[number]; /** A receipt that passed shape validation. */ export interface QaRunReceipt { /** Which check ran. */ kind: QaRunKind; /** The argv that ran. */ command: string[]; /** Root-relative directories or files the run covered (`''` = the whole root). */ roots: string[]; /** Epoch ms the run started, when stated. */ startTime?: number; /** Tool name, when stated. */ toolName?: string; /** Tool version, when stated. */ toolVersion?: string; } /** The receipt, or why its shape is refused. */ export type QaRunParse = { ok: true; receipt: QaRunReceipt; } | { ok: false; codeName: 'E_EVIDENCE_INVALID' | 'E_EVIDENCE_TOOL_FAILED'; reason: string; }; /** Example shape, named in every refusal. */ export declare const QA_RUN_SHAPE_HINT: string; /** * Whether a changed path is an input a QA check reads (T13698): a lint run * owes coverage only for what it lints, a typecheck only for TS sources. * * @param check - The QA check. * @param path - Repo-relative changed path. * @returns True when the check reads the path. * @task T13698 */ export declare function qaRunChecks(check: QaRunKind, path: string): boolean; /** * Validate a parsed receipt's shape and result. * * @param raw - The parsed JSON. * @returns The receipt, or the refusal. * @task T13427 */ export declare function parseQaRunReceipt(raw: unknown): QaRunParse; /** What binding a receipt decided. */ export type QaRunBinding = { ok: false; codeName: 'E_EVIDENCE_STALE' | 'E_EVIDENCE_INSUFFICIENT'; reason: string; } | { ok: true; /** * Changed code paths this receipt's roots do not cover (T13580). Judged * across every receipt of the same kind by {@link qaRunUnionGapReason}. */ uncovered: string[]; /** Dependent packages this receipt's roots do not cover (T13580). */ uncoveredPackages: string[]; /** The change is non-code only: no package affected, no typecheck owed (T13745). */ nonCodeChange?: boolean; /** Changed CLEO config left to `tool:config-schema` (T13778). */ configPaths?: string[]; /** Untracked files outside the change, set aside at bind time (T14000). */ untrackedSetAside?: string[]; }; /** * Bind a receipt to the change it claims to check, or refuse it when it is * older than the change or the change is workspace-wide (see the module doc). * Coverage is not judged here: a receipt reports what it leaves uncovered, * and {@link qaRunUnionGapReason} refuses what every receipt of its kind * leaves uncovered, so two receipts may together cover a change (T13580). * * @param receipt - From {@link parseQaRunReceipt}. * @param receiptPath - Absolute path of the receipt file. * @param root - The task's checkout. * @returns The refusal, or ok with the paths and packages left uncovered. * @task T13427 */ export declare function bindQaRunReceipt(receipt: QaRunReceipt, receiptPath: string, root: string): QaRunBinding; /** * What a receipt's roots leave uncovered of a set of changed paths — the one * coverage rule for binding a receipt at verify time and for judging one * recorded on the default branch after the change merged (T13644). Refuses a * workspace-wide change, which only a whole-project run speaks for. * * @param kind - The check the receipt records. * @param roots - The receipt's normalised roots (`''` = the whole root). * @param root - The checkout the paths are relative to. * CLEO-owned config files are left to `tool:config-schema` (T13778) and * named as `configPaths`, which the gate then requires a config-schema result for. * * @param changed - The changed paths (documentation paths are ignored). * @returns The refusal, or ok with the paths and packages left uncovered. * @task T13427 * @task T13644 * @task T13778 */ export declare function qaRunCoverage(kind: QaRunKind, roots: readonly string[], root: string, changed: readonly string[]): QaRunBinding; /** * Why the package directories a test-run left to a typecheck (T13783) are not * covered by a typecheck in the same write, or null: a whole-project * `tool:typecheck`, or a qa-run typecheck receipt whose roots hold each one. * * @param atoms - The validated atoms of one gate write. * @param dirs - Root-relative package directories owed a typecheck. * @returns The refusal naming the directories, or null. * @task T13783 */ export declare function typecheckCoverageGap(atoms: readonly EvidenceAtom[], dirs: readonly string[]): string | null; /** A bound qa-run receipt as {@link qaRunUnionGapReason} reads it. */ export interface BoundQaRun { /** Which check it records. */ readonly check: QaRunKind; /** Root-relative paths the run covered (`''` = the whole root). */ readonly roots: readonly string[]; /** Changed code paths it left uncovered; absent on atoms recorded before T13580 (they covered all). */ readonly uncovered?: readonly string[]; /** Dependent packages it left uncovered (T13580). */ readonly uncoveredPackages?: readonly string[]; } /** * Why a set of qa-run receipts does not cover the change, or null (T13580). * Receipts of one kind count together: a path is a gap only when every * receipt of that kind leaves it uncovered, so two lint runs over different * roots may cover one change between them. Each receipt was already checked * fresh and passing on its own. * * A kind owes coverage only for the changed paths its tool reads * ({@link qaRunChecks}); a path neither kind reads must still lie under some * receipt's roots, unless a whole-project tool: run speaks for the gate (T13698). * * @param receipts - The bound qa-run receipts of one gate write. * @param wholeProject - A whole-project tool:lint or tool:typecheck is in the gate. * @returns The refusal naming the uncovered paths or packages, or null. * @task T13580 */ export declare function qaRunUnionGapReason(receipts: readonly BoundQaRun[], wholeProject?: boolean): string | null; //# sourceMappingURL=qa-run-binding.d.ts.map