import { PNG } from "pngjs"; import type { CritiqueFinding, CritiqueTile } from "./critique.js"; /** Bump when the critique request/response contract changes in a way that * invalidates persisted findings (rubric semantics, finding schema, tiling * geometry meaning). Part of every cache key and persisted critique. */ export declare const QA_CRITIQUE_CONTRACT_VERSION = 1; /** Default Path B mismatch-ratio threshold. Strict on purpose: reuse trades * essentially nothing for robustness against rasterization noise, and a * looser threshold could hide a sub-threshold real change. */ export declare const DEFAULT_REUSE_MISMATCH_RATIO = 0.001; /** Critique results persisted beside a QA snapshot, enough to decide reuse * later: findings plus the geometry they were judged under. */ export interface PersistedCritique { contract_version: number; /** fnv1a32 of the exact rubric text the findings were judged under. */ rubric_digest: string; outcome: "pass" | "fail"; findings: CritiqueFinding[]; tiles: Array<{ index: number; label: string; x: number; scrollY: number; width: number; height: number; }>; } /** Versioned, canonicalized Path A cache key (observe mode). Field order is * part of the contract — never reorder without bumping the version. */ export declare function qaTileCacheKey(parts: { tilePngSha256: string; rubricDigest: string; provider: string; model: string; viewport: string; deviceScaleFactor: number; theme: string; state: string; tileLabel: string; browserVersion?: string; }): string; export declare function sha256Hex(buf: Buffer | Uint8Array): string; export declare function rubricDigest(rubric: string): string; /** * Pixel-compare one document-space rect across two full-page screenshots. * `sizeMismatch` is true when the rect isn't fully comparable in both images * (page grew/shrank past it) — the caller treats that as changed. */ export declare function rectMismatch(baselineFullPage: PNG, currentFullPage: PNG, rect: { x: number; y: number; width: number; height: number; }, opts?: { pixelThreshold?: number; }): { ratio: number; comparablePixels: number; sizeMismatch: boolean; }; export interface TileReuseDecision { index: number; label: string; reuse: boolean; reason: string; /** Rect mismatch ratio, present when a pixel comparison ran. */ mismatch_ratio?: number; } export interface CritiqueReusePlan { mode: "band-diff"; /** Tiles that must be reviewed fresh, in original order. */ review: CritiqueTile[]; decisions: TileReuseDecision[]; tiles_total: number; tiles_reused: number; tiles_reviewed: number; provider_calls_avoided: number; mismatch_threshold: number; /** Set when the whole baseline was unusable (everything reviews fresh). */ invalidation?: string; } /** * Path B reuse plan: decide per tile whether the baseline run's verdict still * covers it. A tile is reused ONLY when (a) the baseline is valid for this * rubric and contract, (b) no baseline finding overlaps the tile's document * region (a prior failure is never converted into a pass), and (c) its rect * pixel-matches the baseline screenshot at or below the strict threshold. * Everything else reviews fresh — reuse can produce false REVIEWS, never * false passes. */ export declare function planCritiqueReuse(args: { baselineScreenshot: Buffer; baselineCritique: PersistedCritique; currentScreenshot: Buffer; tiles: CritiqueTile[]; rubric: string; mismatchThreshold?: number; }): CritiqueReusePlan; //# sourceMappingURL=qa-reuse.d.ts.map