import type { Message } from "@kenkaiiii/gg-ai"; export interface IdealReviewStats { changedLines: number; toolCalls: number; toolFailures: number; turns: number; writeCalls: number; editCalls: number; bashCalls: number; } export interface IdealReviewDecision { shouldReview: boolean; score: number; reasons: string[]; } export interface ReviewCoverageEvidence { expected: string[]; covered: string[]; missing: string[]; } /** * Harness-owned proof that every successfully changed file was opened with the * read tool after Ideal review began. Model-authored claims never enter it. */ export declare class ReviewCoverageTracker { private readonly cwd; private readonly fileExists; private readonly expected; private readonly covered; private active; /** * `fileExists` is injectable for tests and defaults to the real filesystem. * A file the run created and then deleted can never be re-read, so without * this check it stayed in `missing` forever and the coverage gate re-injected * the same follow-up on every turn. */ constructor(cwd: string, fileExists?: (p: string) => boolean); reset(): void; /** Successful mutations are retained before and during review. */ recordChanged(filePath: string): void; /** Start the evidence window; reads observed before this call never count. */ start(changedFiles?: Iterable): void; /** Called only by the successful read-tool callback. */ recordRead(filePath: string): void; evidence(): ReviewCoverageEvidence; private normalize; private display; } export declare function buildReviewCoverageMessage(missingFiles: readonly string[]): Message; /** * Coverage follow-ups spent before the gate gives up. The gate is fail-closed, * but a file the agent genuinely cannot read (permissions, a path outside the * workspace, a race with an external delete) must not cost an unbounded number * of identical turns — it escalates once and lets the run finish. */ export declare const MAX_REVIEW_COVERAGE_INJECTIONS = 2; /** * Terminal coverage message: stop demanding reads, require an honest statement * of what went unverified in the final answer. */ export declare function buildReviewCoverageEscalationMessage(missingFiles: readonly string[]): Message; /** * Put the harness-owned read checklist on the first Ideal review turn. The * fail-closed follow-up remains as a fallback, but compliant reviews can now * gather all evidence before emitting their single user-facing final answer. */ export declare function withReviewCoverageRequirements(message: Message, missingFiles: readonly string[]): Message; export declare const IDEAL_REVIEW_PROMPT: string; export declare function evaluateIdealReview(stats: IdealReviewStats): IdealReviewDecision; export declare function buildIdealReviewMessage(reasons: readonly string[], driftedFiles?: readonly string[]): Message; /** * Test-drift detector \u2014 the one stranding signal a typechecker is blind to. * Given the set of files the run mutated, return the source files whose sibling * test exists on disk but was NOT touched this run (a green-but-stale test). * * Pure structural check: no sibling test on disk \u2192 no signal, so it stays * silent on projects (or files) without co-located tests. `fileExists` is * injectable for tests; paths are resolved against `cwd` so relative tool paths * and absolute ones compare consistently. */ export declare function detectTestDrift(touchedFiles: Iterable, cwd: string, fileExists?: (p: string) => boolean): string[]; export declare function shouldCountAsRiskyTool(toolName: string): boolean; //# sourceMappingURL=ideal-review.d.ts.map