UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

95 lines • 4.32 kB
/** * Pure opt-in findings adapter. Role: bind one literal declaration to an exact * authorized result, then ask the shared evaluator; return a row for the EXISTING * findings writer. No ledger, evidence discovery, callbacks on restore or I/O. */ import { copyJson, ownData } from '../../../lib/boundedJson.js'; import { bindClaim } from '../../../integrity/claim-binding/bindEvidence.js'; import { boundedText } from '../../../integrity/claim-binding/scope.js'; import { evaluateClaimPair } from '../../../integrity/unsupported-claim/evaluate.js'; import { claimIdentityOf, readClaimVerificationRow, VERIFICATION_LIMITS, } from './verificationRow.js'; /** * Invalid/missing JSON value throws explicitly: replacing it with null would * misrecord the declaration. A malformed optional check is a recorded refusal. * `supported` is possible only after bindClaim establishes an eligible pair; * the standalone evaluator's no-conflict result is never sufficient. */ export function checkFindingClaim(input) { const request = ownData(input.request); if (!Object.hasOwn(request, 'value')) throw new TypeError('Finding claim has no declared value.'); const declaredValue = copyJson(request.value, VERIFICATION_LIMITS.valueBytes, true); let declaredRule; let checkProblem; if (!Object.hasOwn(request, 'check')) checkProblem = 'missing-check'; else { try { const check = ownData(request.check); if (boundedText(check.rule)) declaredRule = check.rule; if (Object.keys(check).some((key) => key !== 'rule') || declaredRule === undefined) checkProblem = 'malformed-check'; } catch { checkProblem = 'malformed-check'; } } if (Object.keys(request).some((key) => !['value', 'check', 'subject', 'predicate'].includes(key))) checkProblem = 'malformed-check'; const base = { kind: 'claim-verification', claimId: claimIdentityOf(input.identity), declaredOn: input.declaredOn, standing: input.standing, iteration: input.iteration, ...(input.turn !== undefined && { turn: input.turn }), checker: { id: 'claim-pair', version: 1 }, ...(input.parentResult !== undefined && { declaredResult: input.parentResult }), ...(declaredRule !== undefined && { declaredRule }), declaredValue, }; const unverified = (reason) => readClaimVerificationRow({ ...base, outcome: 'unverified', reason }); if (input.standing === 'noise') return unverified('ineligible-noise'); if (checkProblem !== undefined) return unverified(checkProblem); if (input.parentResult === undefined) return unverified('missing-result'); const bound = bindClaim({ result: input.parentResult, value: declaredValue, rule: declaredRule }, input.snapshot, input.rules, input.intendedScope); if (bound.kind === 'unverified') return unverified(bound.reason === 'missing-result' && input.retentionLimited === true ? 'retention-limit' : bound.reason); if (Object.hasOwn(request, 'subject') || Object.hasOwn(request, 'predicate')) { try { const subject = ownData(request.subject, ['kind', 'id']); if (subject.kind !== bound.claim.subject.kind || subject.id !== bound.claim.subject.id || request.predicate !== bound.claim.predicate) return unverified('assertion-mismatch'); } catch { return unverified('assertion-mismatch'); } } const reason = evaluateClaimPair(bound.evidence, bound.claim); if (reason !== 'no-conflict' && reason !== 'numeric-leniency' && reason !== 'conflict') return unverified(reason); const resolved = { resultId: bound.resultId, rule: bound.rule, scope: bound.scope, coverage: bound.coverage, ...(bound.period !== undefined && { period: bound.period }), evidence: bound.evidence, claim: bound.claim, }; return readClaimVerificationRow({ ...base, outcome: reason === 'conflict' ? 'contradicted' : 'supported', reason, resolved, }); } //# sourceMappingURL=verificationCheck.js.map