export type AcId = `AC-${number}` | string; export interface TestRef { /** Path relative to `repoRoot`, forward-slashed. */ file: string; /** 1-based line number where the AC token first appeared. */ line: number; /** Trimmed snippet of the matching line (≤120 chars). */ snippet: string; /** Assertion mode only: true when the ref is inside a qualifying span. */ qualifying?: boolean; /** Assertion mode only: true when the ref falls inside a skip/todo/failing span (the "skip dodge"). */ skipped?: boolean; } export interface CoverageScanOptions { /** * Glob-ish patterns to match test files. Default scans the workspace * `packages/**\/*.test.ts`. The implementation supports `**` (any depth) * and `*` (any chars within a segment); no brace expansion or character * classes — keep the convention narrow + dependency-free. */ globs?: string[]; /** * Coverage strictness (phase 108). `mention` (default) = whole-file token * search. `assertion` = an AC ref counts only inside an `it()`/`test()` block * that asserts; mention-only refs are still recorded but tagged * `qualifying: false`. */ mode?: 'mention' | 'assertion'; /** * Phase 239 (phase-qualified coverage scheme): when set (a draft id, e.g. * `'239-01'`), an AC token counts only if it is immediately preceded by * `/` — the prefix form `239-01/AC-3`. Bare and * foreign-phase occurrences are dropped from the result entirely; map * keys stay the bare `AC-N` id. Absent, the scan is byte-for-byte the * historical bare behavior. */ expectedQualifier?: string; } /** * Pure qualifier check (phase 239, T2). True iff the AC token starting at * `tokenOffset` in `text` is immediately preceded by `` `${qualifier}/` ``, * and that prefix is not itself the tail of a longer id (`1239-01/AC-3` * must not satisfy qualifier `239-01`). Works on whatever string the caller * matched the token in (whole file or a single line) — the prefix form * never spans a newline, so a line-scoped check is equivalent. */ export declare function tokenHasExpectedQualifier(text: string, tokenOffset: number, qualifier: string): boolean; /** * Walk the repo and collect a map of AC ids → tests that reference them. * The convention is whole-file text search: any occurrence of `AC-N` inside * a file matched by `globs` counts as one linked test. Comment refs count * too, by design — the gate is binary per AC, not coverage-percentage. */ export declare function scanTestCoverage(repoRoot: string, opts?: CoverageScanOptions): Promise>; /** * Whether any file in the repo matches `globs` at all (Phase 166, T3 fix * round). `uncoveredAcs` alone can't distinguish "no test files matched the * globs" from "files matched fine but this particular AC-N is never * mentioned in any of them" — both produce zero refs. The gate needs this * signal to avoid telling the operator to check their globs when the globs * were never the problem. */ export declare function anyTestFilesMatched(repoRoot: string, globs?: string[]): Promise; /** * Returns the list of AC ids that have zero linked tests. Useful for the * settle gate's refusal message. */ export declare function uncoveredAcs(acIds: string[], coverage: Map): string[]; /** * Assertion mode: AC ids that have ≥1 recorded ref but none that qualifies * (i.e. mentioned somewhere, but never inside an asserting it()/test() block), * where at least one of those non-qualifying refs is NOT skip-caused (e.g. a * bare comment mention with no containing span at all). Mutually exclusive * with `skippedOnlyLinkedAcs` (phase 169): every AC with ≥1 ref and 0 * qualifying refs lands in exactly one of the two buckets. * Empty in mention mode (refs there carry no `qualifying` flag → treated as * not-weak as long as they exist). */ export declare function weaklyLinkedAcs(acIds: string[], coverage: Map): string[]; /** * Assertion mode (phase 169): AC ids that have ≥1 recorded ref, none of * which qualify, where EVERY non-qualifying ref is skip-caused — i.e. every * ref sits inside a `test.skip`/`.todo`/`.failing` span (the "skip dodge"). * Distinct from `weaklyLinkedAcs`, which requires at least one non-qualifying * ref to NOT be skip-caused; the two are mutually exclusive. */ export declare function skippedOnlyLinkedAcs(acIds: string[], coverage: Map): string[]; /** * Phase 167 (T8) — per-file, per-span diagnostic detail for * `cadence verify coverage --explain AC-N`. * * `scanTestCoverage` deliberately collapses per-file profile/span detail * into a flat `qualifying: boolean` — enough for the gate's binary * pass/fail, but not enough to diagnose a refusal without reading engine * source. This is a NEW, separate read path (not a modification of * `scanTestCoverage`) that walks the same glob-matched file set and * preserves that detail: which profile (if any) scanned each file, why * (unclaimed extension vs. a claimed extension with zero recognized * blocks), every span found, and — per occurrence of the target AC token — * which span contains it and a plain-language satisfy/not-satisfy reason. * Read-only: only ever calls `readFile`/`readdir`, never writes anything, * and shares no mutable state with `scanTestCoverage` or the real gate * (`../gates/coverage.ts`), so this addition cannot regress either. */ export interface ExplainSpan { /** Absolute char offset of the span's opener match start. */ start: number; /** Absolute char offset of the span's closing boundary (inclusive). */ end: number; /** 1-based line number of `start`. */ startLine: number; /** 1-based line number of `end`. */ endLine: number; /** True iff a code-mode assertion token was found inside this span. */ hasAssertion: boolean; /** True iff this span's opener marks a test that doesn't run its body * normally (phase 169's "skip dodge", e.g. js/ts's `it.skip`/`test.todo`; * ported onto this diagnostic at merge time so it stays accurate — an * intact assertion inside a skipped test must NOT read as satisfying, * matching `runCoverageGate`'s own real refusal behavior). */ skipped: boolean; } export interface ExplainOccurrence { /** 1-based line number where the AC token occurrence starts. */ line: number; /** Trimmed snippet of the matching line (≤120 chars). */ snippet: string; /** Absolute char offset of the occurrence. */ offset: number; /** The span containing this occurrence, or null if none does. */ span: ExplainSpan | null; /** True iff this occurrence satisfies the configured coverage mode. */ satisfies: boolean; /** Human-readable reason for the satisfy/not-satisfy verdict. */ reason: string; } export interface ExplainFileResult { /** Path relative to `repoRoot`, forward-slashed. */ file: string; /** Lowercase file extension (with leading dot), `''` if none. */ extension: string; /** Id of the profile that scanned this file, or null if unclaimed * (mention mode always reports null — no profile scan is performed). */ profileId: string | null; /** Human-readable reason naming which case applies: no profile for the * extension, a profile that found no test block, or a normal scan. */ profileReason: string; /** Total spans `findSpansForProfile` found in this file (0 in mention * mode, for an unclaimed extension, or for a claimed extension whose * profile recognized no block shape in this file's actual content). */ spansFound: number; /** Occurrences of the target AC token found in this file. */ occurrences: ExplainOccurrence[]; } export interface CoverageExplainResult { /** The AC id being explained, e.g. `'AC-8'`. */ acId: string; /** Coverage mode in effect. */ mode: 'mention' | 'assertion'; /** * Phase 239 (T4, AC-6): the qualifier in effect under * `verification.coverageScheme: 'phase-qualified'`, e.g. `'239-01'`. * Absent under the bare scheme, which keeps the historical result shape * (and the historical rendered report) unchanged. */ expectedQualifier?: string; /** Glob patterns searched (resolved defaults if none configured). */ globs: string[]; /** Whether any file in the repo matched `globs` at all — distinguishes a * glob-configuration problem from "globs matched, this AC just isn't * mentioned anywhere". */ anyFilesMatched: boolean; /** Per-file detail for every glob-matched file, sorted by path. */ files: ExplainFileResult[]; /** True iff at least one occurrence, in any file, satisfies the mode. */ satisfied: boolean; } /** * Walk glob-matched files and, for a single target `acId`, surface every * occurrence together with its containing span (if any) and a plain- * language satisfy/not-satisfy reason. Powers `cadence verify coverage * --explain` (T8, AC-8). Read-only. */ export declare function explainAcCoverage(repoRoot: string, acId: string, opts?: CoverageScanOptions): Promise; //# sourceMappingURL=coverage.d.ts.map