/** * Evidence-based gate validation (ADR-051 / T832). * * Parses and validates evidence atoms for `cleo verify`. Each atom is checked * against the filesystem, git, structured test-run JSON output (vitest / * pytest / cargo-nextest etc.), or a project-resolved toolchain exit code. * Soft evidence (`url:`, `note:`) is accepted without validation. * * Tool resolution is project-agnostic per T1534 / ADR-061: * - {@link resolveToolCommand} maps `tool:` to a runnable command * using `.cleo/project-context.json` and per-`primaryType` fallbacks. * - {@link runToolCached} memoises results per `(cmd, args, head, dirty)` * and serialises concurrent identical runs via a cross-process lock, * preventing the resource thrash observed when multiple `cleo verify` * invocations spawned full toolchains in parallel. * * @task T832 * @task T1534 * @adr ADR-051 * @adr ADR-061 */ import type { EvidenceAtom, GateEvidence, VerificationGate } from '@cleocode/contracts'; import { CANONICAL_TOOLS, type CanonicalTool } from './tool-resolver.js'; /** * Valid tool names recognised by the `tool:` evidence atom. * * Sourced from {@link listValidToolNames} so canonical names + every legacy * alias resolve identically. Use {@link isValidToolName} or pass to * {@link resolveToolCommand} directly — direct array indexing is no longer * the canonical path (post-T1534). * * @task T832 * @task T1534 */ export declare const VALID_TOOLS: readonly string[]; /** * Type of a supported evidence tool. Post-T1534, this is widened to every * canonical tool name plus every alias accepted by {@link resolveToolCommand}. * * Existing callers that assigned `'pnpm-test' | 'biome' | ...` continue to * compile because those literal types remain assignable to `string`. * * @task T832 * @task T1534 */ export type EvidenceTool = CanonicalTool | string; /** * Test whether a string is a recognised tool name (canonical or alias). * * @task T1534 */ export declare function isValidToolName(name: string): boolean; /** * @deprecated Since T1534 — tool commands are resolved per-project from * `.cleo/project-context.json` via {@link resolveToolCommand}. This export * is retained as an empty record for back-compat with downstream callers * that destructured the legacy table; new code MUST call the resolver. * * @task T1534 */ export declare const TOOL_COMMANDS: Record; /** * Minimum evidence required for each verification gate. * * - A single atom kind means at least one atom of that kind MUST be present. * - A tuple of kinds means all listed kinds MUST be present. * - Alternatives are modeled as separate sets — if ANY set is satisfied the * evidence is accepted. * * **Source of truth (T10337):** the underlying spec now lives in * {@link GATE_EVIDENCE_REQUIREMENTS} in `@cleocode/contracts`. This export * is the legacy projection — `Record` — kept for back- * compat with consumers that hard-coded the nested-array shape. New code * SHOULD use {@link validateEvidenceForGate} from `@cleocode/contracts` * directly. * * @task T832 * @task T1515 * @task T10337 * @adr ADR-051 §2.3 */ export declare const GATE_EVIDENCE_MINIMUMS: Record; /** * Minimum LOC reduction percentage required when the `engine-migration` label * is present on a task. * * Tasks claiming to migrate an engine MUST demonstrate a measurable reduction * in lines of code to prevent structural-only migrations (T1604). * * @task T1604 */ export declare const ENGINE_MIGRATION_MIN_REDUCTION_PCT = 10; /** * Result of parsing a raw evidence string into structured atoms. * * @task T832 */ export interface ParsedEvidence { atoms: ParsedAtom[]; } /** * An atom that has been parsed from the CLI syntax but not yet validated * against filesystem / git / tools. * * @task T832 */ export type ParsedAtom = { kind: 'commit'; sha: string; } | { kind: 'files'; paths: string[]; } | { kind: 'test-run'; path: string; } | { kind: 'tool'; tool: string; } | { kind: 'url'; url: string; } | { kind: 'note'; note: string; } | { kind: 'loc-drop'; fromLines: number; toLines: number; } | { kind: 'callsite-coverage'; symbolName: string; relativeSourcePath: string; } | { /** * Decision atom — a brain_decisions row that IS the canonical artifact * for a decision-only task. Satisfies the `implemented` gate when combined * with `files:` pointing to a research note. * * @task T1875 */ kind: 'decision'; /** Decision ID from `brain_decisions.id` (e.g. `"D-arch-001"`). */ decisionId: string; } | { /** * Pull-request atom — references a GitHub PR by number. Validation * resolves the PR via `gh pr view` and checks state=MERGED plus * all required-workflow checks green. Satisfies `implemented`, * `testsPassed`, and `qaPassed` simultaneously (T9838). * * @task T9764 * @task T9838 */ kind: 'pr'; /** PR number (positive integer). */ prNumber: number; } | { /** * Cross-task AC-binding atom — references an acceptance criterion on * another task in the same Saga (or root Epic when no Saga). The atom * carries either the canonical UUIDv4 (`targetAcId`) OR the positional * alias (`targetAcAlias`) — never both, never neither. Optional * `versionPin` captures the target AC's `updated_at` at mint time. * * This entry covers PARSING ONLY (T10506); the 5-check validator * semantics (target exists, target not terminal, AC exists, same-saga * scope) ship in T10507. See ADR-079-r2 §2.1 for the ABNF and §2.4 * for the runtime validator contract. * * @task T10506 * @adr ADR-079-r2 */ kind: 'satisfies'; /** Target task ID — `T<1-7 digits>` per ADR-079-r2 §2.1. */ targetTaskId: string; /** Lowercase UUIDv4 — populated for canonical form; undefined for alias form. */ targetAcId?: string; /** `AC<1-4 digits>` alias — populated for alias form; undefined for UUID form. */ targetAcAlias?: string; /** Optional `@` pin captured at mint time. */ versionPin?: string; }; /** * Parse the CLI `--evidence` string into structured atoms. * * Syntax: * evidence-list := atom ';' atom ';' ... * atom := kind ':' payload * payload for files: comma-separated paths * payload for everything else: opaque string until next ';' * * Delegates the syntactic parse to * {@link parseEvidenceString} in `@cleocode/contracts` (T10337) and wraps the * `EvidenceParseError` in the legacy `CleoError(VALIDATION_ERROR, ...)` * envelope so existing CLI surfaces continue to receive the expected exit * code and `fix:` hint. * * @param raw - Raw CLI string from `--evidence` * @returns Parsed atoms ready for {@link validateAtom} * @throws CleoError(VALIDATION_ERROR) for malformed input * * @example * ```ts * parseEvidence('commit:abc123;files:a.ts,b.ts;tool:biome'); * // => { atoms: [{kind:'commit',sha:'abc123'}, ...] } * ``` * * @task T832 * @task T10337 */ export declare function parseEvidence(raw: string): ParsedEvidence; /** * Result of validating one atom — success carries the validated form * (with sha256 / exit codes populated), failure carries a human-readable * reason string. * * @task T832 */ export type AtomValidation = { ok: true; atom: EvidenceAtom; } | { ok: false; reason: string; codeName: string; }; /** * Validate a single parsed atom against the filesystem / git / tools. * * @param parsed - Parsed atom from {@link parseEvidence} * @param projectRoot - Absolute path to project root (for resolving files, git) * @param taskId - Optional CLEO task ID. When provided, enables branch-scope * check (T9178), content-intersect check (T9245), worktree-aware HEAD * resolution (T-WT-3), and git-show file fallback for branch-only files * (T11959). * @returns Validation outcome with canonicalised form on success * * @task T832 * @task T11959 * @adr ADR-051 §3 */ export declare function validateAtom(parsed: ParsedAtom, projectRoot: string, /** T9178: When provided, validates commit is on task/ branch. */ taskId?: string): Promise; /** * Heuristic guard that decides whether a regex-extracted slash token is a * plausible repository file path rather than a URL or prose fragment. * * A token passes when it either: * - starts with a known {@link REPO_DIR_PREFIXES} directory, OR * - ends with a file extension in {@link REPO_FILE_EXTENSIONS} * * The guard intentionally accepts false negatives (omits exotic paths) rather * than false positives (includes internet hostnames). When a task owner needs * an exotic path captured they can use the explicit `--files` flag on * `cleo add` / `cleo update`. * * @param token - Slash-containing token extracted from AC text. * @returns `true` when the token looks like a repo path. * * @internal * @task T11960 */ export declare function isRepoPathLike(token: string): boolean; /** * Extract the canonical list of files a task's acceptance criteria declare. * * Resolution order: * 1. `task.files` array — authoritative when populated (set via `--files`) * 2. AC string parsing — extract path-like tokens from each * `task.acceptance` string, then filter with {@link isRepoPathLike} * to discard URL/prose false-positives (T11960). * * Returns `null` when the task declares no AC files at all — caller MUST * interpret this as "skip content-intersect" rather than "verify fails". * * @internal * @task T9245 * @task T11960 */ export declare function extractTaskAcFiles(task: { files?: string[] | null; acceptance?: ReadonlyArray | null; }): string[] | null; /** * Resolve a worktree path to the canonical main repo path by parsing * the .git gitlink file. Returns projectRoot as-is for non-worktree dirs. * * When a git worktree is active, `.git` is a plain FILE containing a line of * the form `gitdir: /abs/path/to/main/.git/worktrees/`. Stripping the * last 3 path components from that gitdir path yields the main repo root. * * Used by {@link checkCommitContentIntersect} to ensure task metadata is always * read from the canonical `tasks.db` in the main repository rather than from * the stale point-in-time copy that was bootstrapped into the worktree at spawn * time (Bug C from the E-WORKTREE-IVTR spec). * * @param projectRoot - Absolute path that may be a git worktree or the main repo. * @returns Absolute path to the canonical main repository root. * * @task T-WT-2 * @epic T9586 */ export declare function resolveCanonicalProjectRoot(projectRoot: string): string; export { CANONICAL_TOOLS }; /** * Check that the provided evidence atoms satisfy the LOC-drop requirement for * engine-migration tasks. * * Returns `null` when the requirement is satisfied; otherwise returns a human- * readable reason string suitable for use as an `E_EVIDENCE_INSUFFICIENT` * error message. * * @param atoms - Already-validated evidence atoms. * @param minReductionPct - Minimum reduction percentage required (default: 10%). * @returns `null` on success, error message on failure. * * @task T1604 */ export declare function checkEngineMigrationLocDrop(atoms: EvidenceAtom[], minReductionPct?: number): string | null; /** * The canonical label that triggers callsite-coverage gate enforcement. * * When a task carries this label the `implemented` gate MUST be accompanied * by a `callsite-coverage` evidence atom proving the exported symbol is * referenced from a production callsite. * * @task T1605 */ export declare const CALLSITE_COVERAGE_LABEL = "callsite-coverage"; /** * Check that the provided evidence atoms satisfy the callsite-coverage * requirement for tasks carrying the `callsite-coverage` label. * * Returns `null` when the requirement is satisfied; otherwise returns a * human-readable reason string suitable for use as an `E_EVIDENCE_INSUFFICIENT` * error message. * * @param atoms - Already-validated evidence atoms. * @returns `null` on success, error message string on failure. * * @task T1605 */ export declare function checkCallsiteCoverageAtom(atoms: EvidenceAtom[]): string | null; /** * Check whether a set of validated atoms satisfies the minimum evidence * required for a given gate. * * @param gate - The gate being verified * @param atoms - Validated atoms * @returns null when satisfied; otherwise the reason message * * @task T832 * @adr ADR-051 §2.3 */ export declare function checkGateEvidenceMinimum(gate: VerificationGate, atoms: EvidenceAtom[]): string | null; /** * Detailed variant of {@link checkGateEvidenceMinimum} that returns the * machine-readable failure (with `message` + `hint`) instead of a flat * string. Use this when the caller needs the multi-line CLI `fix:` hint * (T9949) — `E_EVIDENCE_INSUFFICIENT` surfaces in engine-ops.ts populate * `engineError({fix: result.hint})` with this output. * * Returns `null` when the gate is satisfied. * * @param gate - The gate being verified * @param atoms - Validated atoms * @returns `null` when satisfied; `{ message, hint }` when not * * @task T9949 * @adr ADR-051 §2.3 */ export declare function checkGateEvidenceMinimumDetailed(gate: VerificationGate, atoms: EvidenceAtom[]): { message: string; hint: string; } | null; /** * Compose a {@link GateEvidence} record from validated atoms. * * @param atoms - Validated evidence atoms * @param capturedBy - Agent identifier * @param override - True when CLEO_OWNER_OVERRIDE is set * @param overrideReason - Reason supplied with the override * @returns Canonical GateEvidence ready to persist * * @task T832 */ export declare function composeGateEvidence(atoms: EvidenceAtom[], capturedBy: string, override?: boolean, overrideReason?: string): GateEvidence; /** * Result of re-verifying stored evidence at complete time. * * @task T832 */ export interface RevalidationResult { stillValid: boolean; failedAtoms: Array<{ atom: EvidenceAtom; reason: string; }>; } /** * Critical gates for which `override`-only evidence is NEVER accepted. Closes * the override-loophole proven 2026-05-12 — 13 mis-completed tasks in the * 2026-05-11 campaign passed `implemented`/`testsPassed` with override-only * evidence. Audit: `.cleo/rcasd/campaign-validation-2026-05-12/SYNTHESIS.md`. * * Other gates (`qaPassed`, `documented`, `securityPassed`, `cleanupDone`, * `nexusImpact`) MAY still accept `note:` waivers / overrides per ADR-051. * * @task T9245 * @adr ADR-051 */ export declare const CRITICAL_GATES_NO_OVERRIDE: readonly VerificationGate[]; /** * Whether an evidence atom is a "hard" (programmatically-validated) atom. * * Hard atoms — `commit`, `files`, `test-run`, `tool`, `pr`, `decision` — carry * programmatic proof. Soft atoms — `override`, `note`, `url` — do not. The * T9245 critical-gate rule (`implemented`, `testsPassed`) requires at least one * hard atom even under an owner override. * * This is the SINGLE SOURCE OF TRUTH for the predicate. Both the verify-time * acceptance check ({@link ../validation/engine-ops.validateGateVerify}) and the * complete-time re-validation ({@link revalidateEvidence}) MUST use it so the * two checks can never diverge (gh#1105: verify accepted an override+soft-atom * green that complete then reversed). * * @task T9245 * @task T12015 * @adr ADR-051 */ export declare function isHardAtom(atom: EvidenceAtom): boolean; /** * Re-validate stored evidence to detect tampering between verify and complete. * * Hard atoms (commit, files, test-run, tool) are re-executed. Soft atoms * (url, note, override) pass through unchanged. * * T9245: when `gate` ∈ {@link CRITICAL_GATES_NO_OVERRIDE}, override-only * evidence is rejected at re-validation time. Forces the worker to produce * real programmatic proof for `implemented` and `testsPassed`. * * @param evidence - Previously-stored evidence * @param projectRoot - Absolute path to project root * @param gate - Optional gate name; when provided enables the critical-gate * override-rejection check (T9245). Omit for back-compat callers. * @param taskId - Optional CLEO task ID; enables git-show fallback for files * that were on the task branch at verify time but are now on main after * merge (T11959). When provided, sha256 comparison uses the same git-show * resolution path as validate time so the checksums remain consistent. * @returns Revalidation outcome * * @task T832 * @task T9245 * @task T11959 * @adr ADR-051 §5 / §8 (Decision 8) */ export declare function revalidateEvidence(evidence: GateEvidence, projectRoot: string, gate?: VerificationGate, taskId?: string): Promise; //# sourceMappingURL=evidence.d.ts.map