agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
110 lines • 7.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.requireVerificationOnResume = exports.verificationCheckpointOf = exports.readVerificationCheckpoint = void 0;
/**
* One admission boundary for the verifier's private checkpoint carrier.
* Role: join validated observation identities to retained lineage/counters,
* never reconstruct evidence, evaluate a claim or authenticate storage.
* Historical observations without a carrier are readable but supply no grant.
*/
const boundedJson_js_1 = require("../../../lib/boundedJson.js");
const canonicalJson_js_1 = require("../../../lib/canonicalJson.js");
const capture_js_1 = require("../../../integrity/claim-binding/capture.js");
const scope_js_1 = require("../../../integrity/claim-binding/scope.js");
const verificationRow_js_1 = require("./verificationRow.js");
const verificationState_js_1 = require("./verificationState.js");
/** Classify stored rows as data, using the same strict new-row reader on both paths. */
function verificationRowsOf(raw) {
// The legacy optional ledger treats undefined as absence. The NEW evidence
// carrier has no such exception: its own present-only reader stays strict.
const rows = (0, scope_js_1.ownConfigArray)(raw === undefined ? [] : raw, Number.MAX_SAFE_INTEGER);
const observations = [];
for (const row of rows) {
if (row === null || typeof row !== 'object' || Array.isArray(row))
throw new TypeError('Invalid findings verification ledger.');
const kind = Object.getOwnPropertyDescriptor(row, 'kind');
if (kind === undefined || !('value' in kind))
throw new TypeError('Invalid findings verification row kind.');
if (kind.value === 'claim-verification')
observations.push((0, verificationRow_js_1.readClaimVerificationRow)(row));
}
return observations;
}
/** Read a present carrier beside its ledger; the checkpoint owner authenticates origin. */
function readVerificationCheckpoint(raw, ledger) {
const admitted = (0, verificationState_js_1.readVerificationState)(raw, 0);
let largestClaimOrdinal = 0;
const seen = new Set();
// Reuse the dense own-data array owner, not the saved value's iterator.
// No new ledger length cap: older ledger rows retain their existing budget.
for (const observation of verificationRowsOf(ledger)) {
const identity = (0, verificationRow_js_1.readClaimIdentity)(observation.claimId);
if (identity.namespace !== admitted.evidence.namespace ||
!admitted.evidence.runIds.includes(identity.runId) ||
seen.has(identity.ordinal))
throw new TypeError('Invalid findings verification claim lineage.');
seen.add(identity.ordinal);
largestClaimOrdinal = Math.max(largestClaimOrdinal, identity.ordinal);
if (observation.outcome !== 'unverified') {
const resolved = observation.resolved;
const result = (0, capture_js_1.readResultIdentity)(resolved.resultId);
if (result.namespace !== admitted.evidence.namespace ||
!admitted.evidence.runIds.includes(result.runId) ||
result.ordinal >= admitted.nextResultOrdinal)
throw new TypeError('Invalid findings verification result lineage.');
const receipt = admitted.evidence.results.find((item) => item.id === resolved.resultId);
const facts = receipt?.facts?.filter((fact) => fact.entity === resolved.evidence.subject.id &&
fact.field === resolved.evidence.predicate);
if (receipt === undefined ||
receipt.unavailable !== undefined ||
(0, canonicalJson_js_1.canonicalJson)(receipt.scope) !== (0, canonicalJson_js_1.canonicalJson)(resolved.scope) ||
(0, canonicalJson_js_1.canonicalJson)(receipt.coverage) !== (0, canonicalJson_js_1.canonicalJson)(resolved.coverage) ||
(0, canonicalJson_js_1.canonicalJson)(receipt.period) !== (0, canonicalJson_js_1.canonicalJson)(resolved.period) ||
facts?.length !== 1 ||
(0, canonicalJson_js_1.canonicalJson)(facts[0].value) !== (0, canonicalJson_js_1.canonicalJson)(resolved.evidence.value))
throw new TypeError('Recorded comparison does not name its retained receipt.');
}
}
return (0, verificationState_js_1.readVerificationState)(admitted, largestClaimOrdinal);
}
exports.readVerificationCheckpoint = readVerificationCheckpoint;
/**
* Shared by conversation-history and full pause boundaries. Presence is strict:
* undefined, inherited fields and accessors are not absence or live evidence.
*/
function verificationCheckpointOf(container) {
if (container === null || typeof container !== 'object' || Array.isArray(container))
throw new TypeError('Invalid findings verification checkpoint container.');
const descriptor = Object.getOwnPropertyDescriptor(container, 'claimVerification');
if (descriptor === undefined) {
if ('claimVerification' in container)
throw new TypeError('Inherited findings verification state is not a checkpoint.');
return undefined;
}
if (!('value' in descriptor))
throw new TypeError('Findings verification state must be stored data.');
const source = (0, boundedJson_js_1.ownData)(container);
const ledger = (0, scope_js_1.ownConfigArray)(source.findingsLedger === undefined ? [] : source.findingsLedger, Number.MAX_SAFE_INTEGER);
return readVerificationCheckpoint(descriptor.value, ledger);
}
exports.verificationCheckpointOf = verificationCheckpointOf;
/** Never silently discard a previously opted-in verifier on newest-version resume. */
function requireVerificationOnResume(container, enabled) {
const state = verificationCheckpointOf(container);
if (state === undefined && container !== null && typeof container === 'object') {
const ledgerDescriptor = Object.getOwnPropertyDescriptor(container, 'findingsLedger');
if (ledgerDescriptor === undefined && 'findingsLedger' in container)
throw new TypeError('Findings verification ledger must be own stored data.');
if (ledgerDescriptor !== undefined && !('value' in ledgerDescriptor))
throw new TypeError('Findings verification ledger must be stored data.');
if (verificationRowsOf(ledgerDescriptor?.value).length > 0)
throw new TypeError('This saved run has findings verification observations but no retained evidence ' +
'carrier. It is readable history, not a resumable verification checkpoint.');
}
if (state !== undefined && !enabled)
throw new TypeError('This saved run carries findings verification evidence. Continue it with findings ' +
'verification enabled; disabling it would silently discard saved checks.');
return state;
}
exports.requireVerificationOnResume = requireVerificationOnResume;
//# sourceMappingURL=verificationCheckpoint.js.map