/** * Support verification: a port for an independent check of whether a * candidate's value is supported by its evidence, and the immutable record of * what such a check said. * * A {@link CandidateVerification} is a record of a verifier's output, bound to * the exact value and evidence it checked. It is not a trust decision: nothing * in Survey reads it to route, auto-accept, or calibrate a candidate. Survey * ships no verifier implementations; producers or separate adapter packages * implement {@link SupportVerifier}. * * Runtime-neutral (no Node built-ins) so the review workbench bundle can * validate records in the browser. */ export declare const candidateVerificationKind: "survey.candidate-verification"; export type SupportVerificationMethod = "deterministic" | "model" | "human"; export type SupportVerificationResult = "supported" | "contradicted" | "not-addressed" | "abstain"; export type SupportAbstainReason = "malformed" | "empty" | "timeout" | "unsupported" | "error"; export interface SupportEvidence { id: string; excerpt: string; locator: string; context?: string; } export interface SupportVerificationInput { candidateId: string; value: unknown; /** Declared value type when the producer knows it (for example `ReviewValueType`). */ valueType?: string; /** At least one item; ids are unique. */ evidence: SupportEvidence[]; } /** * What a verifier returns. `score` has no meaning unless a calibration record * says otherwise: it is optional, never defaulted, and never feeds a * confidence. An abstention carries its reason and no score. */ export type SupportVerdict = { result: "supported" | "contradicted" | "not-addressed"; score?: number; } | { result: "abstain"; abstainReason: SupportAbstainReason; }; /** The port. Implementations live with producers or in adapter packages. */ export interface SupportVerifier { readonly id: string; readonly version: string; readonly method: SupportVerificationMethod; verify(input: Readonly, options?: { signal?: AbortSignal; }): Promise; } export interface CandidateVerification { /** `sha256:` digest of every other field; recomputed on validation. */ id: string; kind: typeof candidateVerificationKind; schemaVersion: 1; candidateId: string; /** Sorted, unique ids of the evidence the verifier was given. */ evidenceIds: string[]; /** {@link valueDigest} of the value checked. */ valueDigest: string; /** {@link supportVerificationInputDigest} of the full input checked. */ inputDigest: string; verifier: { id: string; version: string; }; method: SupportVerificationMethod; result: SupportVerificationResult; /** Present exactly when `result` is `abstain`. */ abstainReason?: SupportAbstainReason; /** Uncalibrated unless a calibration record says otherwise. Never defaulted. */ score?: number; createdAt: string; } export interface BuildCandidateVerificationInput { input: SupportVerificationInput; verifier: { id: string; version: string; method: SupportVerificationMethod; }; verdict: SupportVerdict; createdAt: string; } /** * `"sha256:" + hex SHA-256` of the canonical JSON of a value: the same * definition as Surface's `valueDigest`, so a record binds to a value the way a * Surface claim does. */ export declare function valueDigest(value: unknown): string; /** Digest of everything a verifier was given: candidate id, value, value type and evidence (ordered by id). */ export declare function supportVerificationInputDigest(input: SupportVerificationInput): string; /** * Builds a frozen record from a verifier's verdict. Throws on a malformed * verdict: use {@link runSupportVerifier} to turn a verifier's failure into an * abstention instead. */ export declare function buildCandidateVerification(input: BuildCandidateVerificationInput): CandidateVerification; /** How long {@link runSupportVerifier} waits when no `timeoutMs` is given. */ export declare const DEFAULT_SUPPORT_VERIFIER_TIMEOUT_MS = 30000; /** * The largest `timeoutMs` {@link runSupportVerifier} accepts: the largest * delay a timer honours (2^31 - 1 ms). A larger delay would be clamped to * 1 ms, turning a long bound into an immediate timeout, so it is refused. */ export declare const MAX_SUPPORT_VERIFIER_TIMEOUT_MS = 2147483647; export interface RunSupportVerifierOptions { /** * Abstain with `timeout` when the verifier has not answered by then. * Defaults to {@link DEFAULT_SUPPORT_VERIFIER_TIMEOUT_MS}; a verifier is * never waited on without a bound. At most * {@link MAX_SUPPORT_VERIFIER_TIMEOUT_MS}. */ timeoutMs?: number; /** Clock for `createdAt`; defaults to the current time. */ now?: () => string; } /** * Calls a verifier and records what it said. A verifier that throws abstains * with `error`, one that returns nothing with `empty`, one that returns a * malformed verdict with `malformed`, and one that exceeds `timeoutMs` * (default {@link DEFAULT_SUPPORT_VERIFIER_TIMEOUT_MS}) with `timeout`. None of these ever records a pass or a fail. * * Throws only for caller errors: a malformed input, or a verifier without a * usable identity (a record needs one). */ export declare function runSupportVerifier(verifier: SupportVerifier, input: SupportVerificationInput, options?: RunSupportVerifierOptions): Promise; /** * Validates a record read back from storage and returns a frozen copy. Throws * on any unknown field, inconsistent verdict, or an id that is not the digest * of the record's own fields (an edited or inconsistent record). The id is a * content digest, not a signature: it does not prove who wrote the record, and * a record rebuilt with a recomputed id validates. */ export declare function validateCandidateVerification(value: unknown): CandidateVerification; /** The candidate a fold reads records for: its id and its value as it is now. */ export interface CandidateVerificationSubject { candidateId: string; value: unknown; valueType?: string; /** When supplied, records must also match the full input digest. */ evidence?: SupportEvidence[]; } export type CandidateVerificationStatus = "not-evaluated" | "abstained" | "evaluated"; export type CandidateVerificationInapplicableReason = "other-candidate" | "value-changed" | "input-changed"; export interface FoldCandidateVerificationsResult { /** * `not-evaluated` when no record applies to the subject's current value, * `abstained` when every applicable record is an abstention, `evaluated` * when at least one applicable record carries a verdict (supported, * contradicted or not-addressed). Not itself a verdict. */ status: CandidateVerificationStatus; /** Valid records bound to this candidate and value, ordered by id. Abstentions included. */ applicable: readonly CandidateVerification[]; /** Valid records bound to another candidate, value, or input. */ inapplicable: readonly { record: CandidateVerification; reason: CandidateVerificationInapplicableReason; }[]; /** Records that failed validation, by input position. Never read further. */ rejected: readonly { index: number; reason: string; }[]; } /** * Sorts records for one candidate into those that apply to its current value, * those bound to something else, and those that failed validation. Never * selects a winner among applicable records and never derives a trust state. */ export declare function foldCandidateVerifications(subject: CandidateVerificationSubject, records: readonly unknown[]): FoldCandidateVerificationsResult;