import type { ReviewDecision, ReviewItem } from "./review-resource.js"; /** * Decisions across review rounds (#295). * * A new extraction of the same document gives every review item a new identity, * so on its own every re-extraction sends every field back to review. Given the * producer's stable slot identity and per-candidate version identity, a * decision on a slot whose candidates did not change is carried forward to the * new round, and a decision that a later one replaces is marked superseded. * * Vocabulary follows the round receipts producers already keep: a decision is * `carried-forward` (made in an earlier round and still holding because its * candidates are unchanged) or `affirmed` (made against this round's item). * * Survey does not invent slot or version identities: they come from the * producer, and every item and candidate must carry one. Survey additionally * compares each candidate's value, full locator, source evidence and full * claim target, so a * decision is never carried across a candidate whose content changed, even if a * producer reused a version identity. * * Both records are content-addressed (`id` is a digest of every other field) * and immutable: a record that changes is a new record. */ export declare const decisionCarryForwardKind: "survey.decision-carry-forward"; export declare const decisionSupersessionKind: "survey.decision-supersession"; /** How a decision reads in a round. */ export type DecisionBasis = "carried-forward" | "affirmed"; /** The terminal resolution a decision reached, as carry-forward reads it. */ export type CarriedResolution = "accepted" | "rejected" | "could_not_confirm"; /** One review item in a round, with the producer's slot and version identities. */ export interface RoundReviewItem { readonly item: ReviewItem; /** Producer slot identity: the same field of the same source lineage across rounds. */ readonly slotId: string; /** Producer version identity of every candidate of `item`, keyed by candidate id. */ readonly candidateVersionIds: Readonly>; } /** A decision made in an earlier round, with the round item it was made on. */ export interface PriorRoundDecision extends RoundReviewItem { readonly decision: ReviewDecision; } /** A decision named by content: its resource name and the digest of its canonical bytes. */ export interface DecisionReference { readonly name: string; readonly digest: string; } export interface DecisionCarryForward { /** `sha256:` digest of every other field; recomputed on validation. */ readonly id: string; readonly kind: typeof decisionCarryForwardKind; readonly schemaVersion: 1; readonly priorDecision: DecisionReference; readonly slotId: string; /** Sorted, unique version ids of the slot's candidates, identical in both rounds. */ readonly versionIds: readonly string[]; readonly roundId: string; /** The new round's review item the decision now applies to. */ readonly reviewItemName: string; /** The new round's candidate the prior decision selected, when it selected one. */ readonly candidateId?: string; readonly resolution: CarriedResolution; readonly basis: "carried-forward"; } /** * Why a decision was superseded: its slot's candidates changed and the new * version was decided (`candidate-changed`), or the unchanged slot was * reviewed again and decided anew (`re-reviewed`). */ export type SupersessionReason = "candidate-changed" | "re-reviewed"; export interface DecisionSupersession { /** `sha256:` digest of every other field; recomputed on validation. */ readonly id: string; readonly kind: typeof decisionSupersessionKind; readonly schemaVersion: 1; readonly priorDecision: DecisionReference; readonly newDecision: DecisionReference; readonly slotId: string; readonly reason: SupersessionReason; } /** * Which prior resolutions may be carried forward. Only `accepted` is carried * unless a policy names others explicitly: a rejection or a could-not-confirm * is a judgment about evidence a new round may have changed around it. */ export interface CarryForwardPolicy { readonly carry: readonly CarriedResolution[]; } export declare const defaultCarryForwardPolicy: CarryForwardPolicy; export type NeedsReviewReason = /** No prior decision was made on this slot. */ "no-prior-decision" /** The slot's candidate versions differ from the ones the prior decision saw. */ | "candidate-changed" /** A version id matched, but the candidate's value, locator, source or claim target did not. */ | "candidate-content-changed" /** The prior decision's resolution is not one the policy carries. */ | "resolution-not-carried" /** More than one live prior decision names this slot. */ | "ambiguous-prior-decisions"; export interface CarriedForwardItem { readonly item: RoundReviewItem; readonly carryForward: DecisionCarryForward; } export interface NeedsReviewItem { readonly item: RoundReviewItem; readonly reason: NeedsReviewReason; /** The prior decision the item could not inherit, when there was one. */ readonly priorDecision?: DecisionReference; } export interface SplitRoundForCarryForwardInput { /** Identity of the new round. */ readonly roundId: string; readonly items: readonly RoundReviewItem[]; readonly priorDecisions: readonly PriorRoundDecision[]; /** Supersessions already recorded: a prior decision they name is no longer live. */ readonly supersessions?: readonly DecisionSupersession[]; readonly policy?: CarryForwardPolicy; } export interface SplitRoundForCarryForwardResult { readonly carriedForward: readonly CarriedForwardItem[]; readonly needsReview: readonly NeedsReviewItem[]; } /** * Splits a new round's items into those that inherit a prior decision * (with a {@link DecisionCarryForward} record naming it) and those that need * review. Pure; performs no I/O. An item carries forward only when exactly one * live prior decision names its slot, the slot's candidates have the same * version ids in both rounds, each candidate's value, locator, excerpt and * source are unchanged, and the policy carries the prior resolution. */ export declare function splitRoundForCarryForward(input: SplitRoundForCarryForwardInput): SplitRoundForCarryForwardResult; export interface BuildDecisionSupersessionInput { readonly prior: PriorRoundDecision; /** The new round's item the new decision was made on. */ readonly item: RoundReviewItem; readonly decision: ReviewDecision; } /** * Records that `decision`, made on the new round's item for the same slot, * replaces `prior`. The reason is derived: `candidate-changed` when the slot's * candidate versions or content differ, `re-reviewed` when they do not. */ export declare function buildDecisionSupersession(input: BuildDecisionSupersessionInput): DecisionSupersession; /** The name and canonical digest of a decision. */ export declare function decisionReference(decision: ReviewDecision): DecisionReference; /** * The terminal resolution a decision reached: `could_not_confirm`, `rejected` * for a rejected status, `accepted` for a verified or assumed one. Undefined * for a decision that reached none (a `proposed` status without * could-not-confirm). */ export declare function decisionResolution(decision: ReviewDecision): CarriedResolution | undefined; /** Validates a stored carry-forward record: its shape and its content-addressed id. */ export declare function validateDecisionCarryForward(value: unknown): DecisionCarryForward; /** Validates a stored supersession record: its shape and its content-addressed id. */ export declare function validateDecisionSupersession(value: unknown): DecisionSupersession;