agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
102 lines • 5.52 kB
JavaScript
;
/**
* delivered — one declared claim of an answer about to be DELIVERED, judged
* for answer validation (`answer-validation/agentChecks.ts` turns the verdict
* into a report row).
*
* Pattern: pure function over one `check.ts` · `compareClaim` result.
* Role: the claim seam's verdict when it can WITHHOLD an answer. It reads
* the detector's own selection (`compareClaim`: every row this run
* settled for the declared `(entity, field)`) and adds the rules a
* verdict that governs delivery needs, because that contract is
* unscoped: rows from ANY tool result, with no scope or age check,
* and any result carrying the semantics marker settles a fact — so
* any row may be forged, foreign or stale.
*
* THE LAW — a reading can only withhold. With no reading the claim is not
* checked (`uncollected`, `not-applicable`), and ONE more reading of the fact,
* wherever it lands, never makes the verdict more permissive: a forged or
* stale row can at most withhold an answer, never deliver one or make it
* read "known". Pinned by the monotonicity property in
* `test/answer-validation/agentChecks.test.ts`. That is why:
* - AGREEMENT IS NEVER SUPPORT. It is `agrees` — `not-applicable`, exactly as
* silent as no reading at all — and only the app's own checks can pass a
* report. A contradiction still withholds.
* - EVERY READING COUNTS, never the latest alone. A reading that settled
* nothing (an `unknown(…)` Claim, a bare `null` or doubt word) beside the
* answer's value, readings that disagree, and a reading that is not a
* well-formed Claim each withhold, whatever else the run read.
* - A CONTRADICTION FOUND IS REPORTED AS ONE. If the answer contradicts ANY
* value the run read, the verdict is a contradiction — `contradicts` when
* it contradicts every value read, `contradicts-a-reading` when the
* readings themselves differ — never relabelled "could not tell" by
* whatever else was read (a forged `null` beside a real reading included).
* Withheld either way; only the label is at stake, and the label is honest.
* - DOUBT IS NEVER AGREEMENT. Doubt on both sides (`null` or `'unknown'` —
* in any case or spacing — or an unknown Claim) withholds; only an absence
* a tool DECLARED (`known(null)`) agrees with the answer's doubt.
* - VALUES COMPARE UNDER THE DECLARED NORMALIZATION (`evaluate.ts` ·
* `compareClaimValues`), never by exact JSON: `'Settled '` agrees with
* `'settled'`, `42.5` with `'42.50'`. Kinds that cannot be compared safely
* are `incomparable`, never `contradicts`.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.judgeDeliveredClaim = void 0;
const evaluate_js_1 = require("./evaluate.js");
/** Readings that are values: more than one exact key (or one with none) is a dispute. */
function disputed(values) {
if (values.length < 2)
return false;
const keys = values.map((value) => (0, evaluate_js_1.claimValueKey)(value));
return keys.includes(undefined) || new Set(keys).size > 1;
}
/** A declared absence (`known(null)`, or a declared doubt word): the one doubt a value settles. */
const declaredAbsence = (shape) => shape.kind === 'value' && shape.declared && (0, evaluate_js_1.claimShapeOf)(shape.face).kind === 'doubt';
/**
* Judge one compared claim for delivery, over EVERY reading of the fact this
* run made. Pure and monotone: a reading added anywhere never turns a
* withholding verdict into `agrees`, `declined` or `uncollected`.
*/
function judgeDeliveredClaim(comparison) {
if (comparison.kind === 'omitted')
return 'omitted';
if (comparison.kind === 'uncollected')
return 'uncollected';
const answer = (0, evaluate_js_1.claimShapeOf)(comparison.claimed);
const readings = comparison.rows.map((row) => ({
value: row.value,
shape: (0, evaluate_js_1.claimShapeOf)(row.value),
}));
if (answer.kind === 'malformed')
return 'incomparable';
const malformed = readings.some((r) => r.shape.kind === 'malformed');
const doubts = readings.filter((r) => r.shape.kind === 'doubt');
const values = readings.filter((r) => r.shape.kind === 'value');
if (answer.kind === 'doubt') {
// The answer claims nothing: only a reading that ALSO settled nothing
// makes this agreement on doubt, which verifies nothing.
if (malformed)
return 'incomparable';
if (doubts.length > 0)
return 'doubt-on-both-sides';
return values.every((r) => declaredAbsence(r.shape)) ? 'agrees' : 'declined';
}
// A contradiction of any value read is the verdict, whatever else was read.
const results = values.map((r) => (0, evaluate_js_1.compareClaimValues)(r.value, comparison.claimed));
if (results.includes('contradicts')) {
return results.every((result) => result === 'contradicts')
? 'contradicts'
: 'contradicts-a-reading';
}
if (malformed)
return 'incomparable';
if (disputed(values.map((r) => r.value)))
return 'disputed';
if (doubts.some((r) => r.shape.kind === 'doubt' && r.shape.declared))
return 'settled-unknown';
if (doubts.length > 0)
return 'settled-doubt';
return results.every((result) => result === 'agrees') ? 'agrees' : 'incomparable';
}
exports.judgeDeliveredClaim = judgeDeliveredClaim;
//# sourceMappingURL=delivered.js.map