import type { Change } from './cluster.js'; import type { NotObserved, RunReport } from './format.js'; /** * A claim, and what the run did with it. * * ## The half nobody asks for * * Everything else in this package answers *what changed*. That is not the * question an agent that just edited a component is asking. It already knows what * it meant to do; what it cannot know is whether the edit landed, whether it * landed only where it was supposed to, and whether the thing it did not mean to * touch moved anyway. * * So the agent declares first — *I am changing `Button`, paint only, at most 12 * subjects* — and the run is read back against the declaration. Three arms come * out, and they are three different products: * * - **Delivered.** The change happened where it was declared. Confirmation, and * the cheapest of the three. * - **Unclaimed.** Something moved that no claim covers. The collateral to fix, * or to name in the proposal before a human finds it. * - **Undelivered.** A claim that matched nothing. *The edit did not take* — * wrong file, dead branch, a rule something else overrides, a stale build. * * The third arm is the one aimed at the failure mode an agent actually has: * acting, observing nothing, and proceeding on the belief that the action landed. * A picture cannot produce it. A build with no diff and a build where the edit * never ran are the same image, and every tool whose output is a score over two * PNGs reports them identically. * * It also disciplines the other two. An agent that claims everything so nothing * can ever be unclaimed walks straight into arm three, because a claim with no * matching change is reported rather than absorbed. Over-claiming is visible by * construction, not by policy. * * ## Declared before, not after * * A claim read out of the diff is not a claim. This function takes the * declaration as an input and never derives one, which is what keeps the * adjudication from scoring the run against itself. * * ## Why an undelivered claim has two different answers * * `Button` was claimed and nothing about `Button` changed. That is either * * - the run rendered `Button` — in this many subjects — and it did not move, so * the edit did not take; or * - the run never rendered `Button` at all, so the claim was not checked and * nothing here may be read as evidence about it. * * Those are opposite instructions. The first sends an agent back to its own edit; * the second sends it to the subject list, or to the provenance that would have * named the component. The census in * [`CompositionReport`](./composition.ts) is what separates them, and where a run * kept no census this says *that*, rather than collapsing the pair into the * reading that happens to be more flattering. * * ## The relationship to core's `adjudicate` * * `@variance-authority/core` adjudicates a **docket** — roots with bands, * impacts, and a project policy — which exists while a run is in memory. A run * report keeps no roots (see [`format.ts`](./format.ts): what is kept is what a * sentence needs), so this adjudicates at the resolution the artifact actually * recorded: the component and the shape. It is the same three arms against less * evidence, and the fields it cannot check it names instead of ignoring. */ /** What a claim may be made about, at the resolution a run report keeps. */ export type ClaimRootKind = 'component' | 'shape'; export interface Claim { /** * What the change is about: `component:Button`, `shape:`, or a * bare name read as a component. * * Matched exactly. A prefix match would let a claim about `Button` silently * authorize a change to `ButtonGroup`, which is the one thing a declaration * must never do. */ readonly root: string; /** Why. Never matched on; carried into the answer so a reader has the context. */ readonly reason: string; /** * Cap on how many subjects the change may reach. * * The most useful field in practice, and the one nobody checks unaided. "I * meant to restyle `Button`" is almost always true; "I meant to restyle * `Button` in 3 subjects" is the part that turns out to be 40. */ readonly maxSubjects?: number; } export type ClaimVerdict = /** Matched, within its declared bound. */ 'delivered' /** Matched, and reached further than declared. Still the intended change. */ | 'overreached' /** Matched nothing, and the run watched it. The edit did not take. */ | 'undelivered' /** Matched nothing, and the run could not have seen it either way. */ | 'unobservable'; export interface ClaimOutcome { readonly claim: Claim; readonly verdict: ClaimVerdict; /** Changes this claim accounts for, most widespread first. */ readonly changes: readonly Change[]; /** Subjects reached, deduplicated across the matched changes. */ readonly subjects: readonly string[]; /** One sentence, ready to print, naming the next move rather than the state. */ readonly because: string; } export interface UnclaimedChange { readonly change: Change; readonly because: string; } export interface RunAdjudication { readonly claims: readonly ClaimOutcome[]; /** Changes no claim covers. Arm two, in report order. */ readonly unclaimed: readonly UnclaimedChange[]; /** * Changed subjects that produced no shape at all. * * Never folded into either arm. A run that read no markup for a subject, or * saw only its accessibility tree change, cannot say what moved there, so it * cannot say whether a claim covers it — and counting these as unclaimed would * invent collateral out of missing evidence. */ readonly ungrouped: readonly string[]; /** * Subjects the run meant to observe and did not. * * Carried because it bounds every other line here. A claim checked against a * run that failed on 50 of 300 subjects is a claim checked against 250, and an * agent told `delivered` without being told that has been told something the * run never established. */ readonly blind: readonly NotObserved[]; /** * The worst thing present, in the order an agent should act on it. * * `unmet` outranks `review`: a claim that did not land means the agent's own * last action failed, and there is no point triaging collateral from an edit * that never happened. */ readonly verdict: 'clean' | 'review' | 'unmet'; } export interface AdjudicateOptions { /** * Claim fields the caller supplied that this resolution cannot check. * * The boundary that parses agent input passes them through so the answer can * say so. Silently dropping a declared band would tell an agent its band claim * held when nothing looked at it. */ readonly unchecked?: readonly string[]; } /** Adjudicate a run against what its author said they were doing. */ export declare function adjudicateRun(report: RunReport, claims: readonly Claim[], options?: AdjudicateOptions): RunAdjudication; /** `component:Button`, `shape:ab12…`, or a bare name read as a component. */ export declare function parseRoot(root: string): { kind: ClaimRootKind; name: string; }; /** * The adjudication as the thing an agent reads before deciding what to do next. * * Ordered by what it should act on, not by what the run computed first: * undelivered claims lead, because an agent triaging collateral from an edit that * never happened is an agent about to make its second mistake. */ export declare function describeAdjudication(result: RunAdjudication): string; //# sourceMappingURL=intent.d.ts.map