import type { Command } from "commander"; import type { EmitContext, HarneryProgramContext } from "../commander.js"; import { type QaRunContext, type QaRunResult } from "../lib/browser/qa-run-contracts.js"; export declare const QA_RECORD_EVIDENCE_SCHEMA_VERSION: 1; /** The evidence document is copied into the run directory beside the result: * the run identity's job_digest is taken over it, so without the copy nothing * downstream could re-derive the digest. qa-run writes `job.json` for the same * reason; the manual name keeps the two from being confused. */ export declare const QA_RECORD_EVIDENCE_FILENAME = "manual-evidence.json"; /** argv marker for a hand-performed check. The contract types argv as a string * array and consumers print it, so an empty array would render as a command * that ran with no arguments. A single explicit marker reads as "no process * executed" and can never be mistaken for a re-runnable command line. */ export declare const QA_RECORD_MANUAL_ARGV: readonly [""]; export type QaManualOutcome = "passed" | "failed" | "unknown"; /** One check a human or agent performed by hand. */ export interface QaManualCheck { /** Context the check was performed in; matches a `contexts[].id` when the * document declares contexts. */ context_id: string; /** Stable check identifier. Prefix with `manual:` by convention. */ check_id: string; outcome: QaManualOutcome; /** What the recorder observed. Carried into the result's `failures` field. */ notes?: string[]; /** Files that back the observation. Every path must exist on disk. */ artifacts?: { png?: string; html?: string; json?: string; }; /** Time the check took, when the recorder measured it. */ wall_time_ms?: number; } export interface QaManualEvidence { schema_version: typeof QA_RECORD_EVIDENCE_SCHEMA_VERSION; /** Who performed the checks (agent name or operator identity). */ recorded_by: string; /** Why the runner could not be used. Required: a hand record with no stated * reason is an assertion, not evidence. */ reason: string; checks: QaManualCheck[]; /** Declared contexts. Absent: derived from the checks' context IDs. */ contexts?: QaRunContext[]; } export type QaManualEvidenceValidation = { ok: true; evidence: QaManualEvidence; } | { ok: false; errors: string[]; }; /** Artifact paths are resolved against the directory holding the evidence * document, not the working directory: an evidence file names the captures * sitting beside it, and that stays true wherever it is recorded from. */ export declare function resolveArtifactPath(baseDir: string, path: string): string; /** * Validate an untrusted evidence document. Every structural problem, every * missing artifact, and every secret-bearing field is reported at once, before * anything is written: a caller fixes the document in one pass, and a * half-valid record never reaches disk. */ export declare function validateManualEvidence(value: unknown, options: { baseDir: string; }): QaManualEvidenceValidation; /** Contexts the result reports: the document's own declarations when it has * them, otherwise one derived per distinct check context ID. Derivation reads * the runner's `--` convention when the ID follows it * and records `unknown` rather than guessing when it does not. */ export declare function deriveContexts(evidence: QaManualEvidence): QaRunContext[]; /** One git probe for the identity block, matching qa-run. Failure is not an * error: work outside any repository legitimately records "unknown". */ export declare function probeRevision(): { tested_revision?: string; worktree_dirty?: boolean; } | undefined; export interface BuildManualResultInput { evidence: QaManualEvidence; target: string; mode: "signoff" | "review"; /** Parent directory; the result lands in `/run-/`. */ outParent: string; /** Pre-minted run ID (tests); default crypto.randomUUID. */ runId?: string; /** Directory the artifact paths resolve against (the evidence file's dir). */ baseDir: string; revisionProbe?: { tested_revision?: string; worktree_dirty?: boolean; }; /** Completion instant (tests); default now. */ completedAt?: Date; } /** * Build the QaRunResult for a validated evidence document. Pure apart from the * host sample and the clock, so the shape is testable without touching disk. */ export declare function buildManualResult(input: BuildManualResultInput): QaRunResult; export interface QaRecordWritePaths { runDir: string; resultPath: string; evidencePath: string; statusPath: string; latestPath: string; } /** * Write the run directory exactly the way the runner does: the result, the * source document, a terminal status document, and the parent's latest.json * pointer written temp-then-rename so a reader never sees a torn write. */ export declare function writeManualRun(result: QaRunResult, evidence: QaManualEvidence): QaRecordWritePaths; export interface QaRecordOutcome { /** 1 usage or validation error · 2 verdict failed · 4 verdict incomplete. * Never 0: a hand-recorded result cannot report a pass. */ exit: 1 | 2 | 4; result?: QaRunResult; paths?: QaRecordWritePaths; error?: string; /** Individual validation errors, all of them, when the document was bad. */ evidenceErrors?: string[]; } export interface QaRecordInput { target: string; evidencePath: string; mode?: string; outDir?: string; /** Lazy default so invalid evidence does not create an empty artifact workspace. */ defaultOutDir?: () => string; runId?: string; completedAt?: Date; /** Injectable for tests; default: the real git probe. */ revisionProbe?: () => { tested_revision?: string; worktree_dirty?: boolean; } | undefined; } /** * Pure core of qa-record: read the evidence document, validate it completely, * build the result, and write the run directory. The commander action is a * thin wrapper over this so the whole path tests without a CLI harness. */ export declare function recordManualQa(input: QaRecordInput): QaRecordOutcome; export declare function registerQaRecordCommand(program: Command, emit: EmitContext, context?: HarneryProgramContext): void; //# sourceMappingURL=qa-record.d.ts.map