import type { ContractPlanSnapshot } from './contract-plan.js'; /** * Contract satisfaction for `execute_plan`, keyed on STABLE TASK IDENTITY. * * Titles are prose a reviewer must retype; IDs (`I-1`, `I-2`, …) are stable keys parsed out of * the plan's own `### Task : …` headings. Matching on titles made a reviewer's paraphrase * indistinguishable from unfinished work, so green tests plus a reworded title terminated as * `failed`. Matching on IDs removes that whole failure class. * * The result is deliberately NOT a boolean. `matched` (did we understand which tasks the * reviewer is talking about?) and `allDone` (did the reviewer say they are finished?) are * different questions with different owners: a match failure is OUR plumbing breaking, a * not-done status is the work genuinely being incomplete. Collapsing them is what caused * engine bugs to be reported to callers as "your work isn't done". */ export interface DispatchedContractTask { readonly id: string; readonly title: string; } export interface ContractMatchResult { /** Did every reviewer entry resolve one-to-one onto a dispatched task id? */ readonly matched: boolean; /** Only meaningful when `matched` is true. */ readonly allDone: boolean; /** Always populated — FR-11 requires the diagnostic to name what WOULD have matched. */ readonly availableTaskIds: readonly string[]; /** Ids the reviewer sent that we did not dispatch. Empty when `matched`. */ readonly unknownIds: readonly string[]; /** Ids we dispatched that the reviewer never mentioned. Empty when `matched`. */ readonly missingIds: readonly string[]; /** Ids the reviewer marked `done`. Only meaningful when `matched`. */ readonly doneIds: readonly string[]; /** Ids the reviewer did NOT mark done — the answer to "which task isn't finished?". */ readonly notDoneIds: readonly string[]; } /** Derive the dispatched task records from a parsed plan. */ export declare function dispatchedTasksFromSnapshot(snapshot: ContractPlanSnapshot): DispatchedContractTask[]; /** * Pull a task id out of ANY reasonable selector spelling. * * Task identity is one scheme — the id — and this is the single place a caller-supplied string * becomes one. The id is embedded in the heading itself (`### Task I-1: Do the thing (← AC-1.1)`), * so every spelling below resolves through the SAME key rather than through a parallel * title-comparison path: * * "I-1" → I-1 * "Task I-1" → I-1 * "Task I-1: Do the thing (← AC-1.1)" → I-1 * "### Task I-1: Do the thing" → I-1 * * That matters because selectors are hand-authored against a rendered plan. Requiring a * byte-exact title was the selector-side twin of the reviewer-echo bug: a caller who copied a * heading and dropped the `(← AC-…)` annotation got `no_match` on correct input. */ export declare function extractTaskId(selector: string): string | null; export type SelectorResolution = { ok: true; ids: string[]; } | { ok: false; unresolvable: string[]; duplicated: string[]; availableTaskIds: string[]; }; /** * Resolve caller-supplied task selectors onto dispatched task ids, one-to-one. An empty * selector list means "every task" and is the caller's business, not this function's. */ export declare function resolveSelectors(selectors: readonly string[], dispatched: readonly DispatchedContractTask[]): SelectorResolution; /** FR-11 — name what WOULD have matched, not only what failed. */ export declare function describeSelectorFailure(r: Extract): string; /** * Resolve reviewer output against the dispatched tasks. Never throws: malformed reviewer output * is an unmatched result, not an exception, because the caller must be able to distinguish it * from incomplete work rather than from a crash. */ export declare function contractMatchFromReviewer(parsedData: unknown, dispatchedTasks: readonly DispatchedContractTask[] | undefined): ContractMatchResult; /** * Per-task completion as a percentage — the answer to "how much of the plan actually landed?". * * Derived from the reviewer's per-task verdicts rather than being a fixed score, so a run that * finished 3 of 4 tasks reports 75 and names the fourth. Returns null when matching failed: we * genuinely cannot score it, and inventing a number would be worse than saying so. */ export declare function taskCompletionPercent(result: ContractMatchResult): number | null; /** FR-11 — a diagnostic that names what would have matched, not only what failed. */ export declare function describeContractMismatch(result: ContractMatchResult): string; //# sourceMappingURL=contract-match.d.ts.map