aere-quantum/conformance/verdict.mjs

41 lines
3.4 KiB
JavaScript

// verdict.mjs: the ONE verdict form of the suite. Whatever the artifact (an AIP-23 envelope, a payment receipt, a market timeline,
// a dataset answer), the verdict says, for each of four levels, PASSED, FAILED or NOT_MEASURED, with the named reason:
//
// integrity the artifact is what it says: its hashes bind its content, and the rules it declares (a policy, deadlines, a
// window, Merkle paths, a payout) hold when recomputed from the evidence supplied
// authenticity the signature the artifact carries verifies
// anchoring its statementHash is recorded in the notary contract, under a state root that a post-quantum anchor covers
// finality that anchor's post-quantum certificate verifies; the finality is the one of the chain it was notarized on
//
// A level nobody judged is NOT_MEASURED and says why (`cause`). The verdict is INVALID when a level FAILED; PARTIAL when nothing
// failed but something the artifact CLAIMS was not measured (a notarization claim not checked offline, a signature scheme the
// verifier cannot check, a timeline that is not terminal, a trust chain no witness fixed in time, a presentation judged without the
// verifier's audience, nonce or trusted issuers, a credential whose status list was not read); VALID otherwise, and only with integrity PASSED. `failed` is the sorted
// list of the rule ids that refused: the suite compares it as an exact set.
export const LEVELS = ['integrity', 'authenticity', 'anchoring', 'finality'];
/** Causes that leave a claim of the artifact unmeasured: nothing failed, and the verdict still cannot be VALID. */
// 'not-supplied' (2026-10-05): the artifact binds itself to something of the VERIFIER (its audience, its nonce, the issuers it trusts)
// and the verifier did not bring it, so the check was not made.
export const CAUZE_PARTIALE = ['claim-not-checked', 'unmeasurable', 'pending', 'incomplete', 'unwitnessed', 'not-supplied'];
export function acumulator() { return Object.fromEntries(LEVELS.map((l) => [l, { failed: [], motive: [], passed: [], nm: [] }])); }
export const pica = (acc, level, rule, motiv) => { acc[level].failed.push(rule); if (motiv) acc[level].motive.push(motiv); };
export const trece = (acc, level, ce) => { acc[level].passed.push(ce); };
export const nemasurat = (acc, level, cause, reason) => { acc[level].nm.push({ cause, reason }); };
export function verdictUnic(artifact, acc) {
const levels = LEVELS.map((l) => {
const a = acc[l];
if (a.failed.length) return { level: l, state: 'FAILED', rules: [...new Set(a.failed)].sort(), reason: [...new Set(a.motive)].join('; ') };
const partial = a.nm.find((x) => CAUZE_PARTIALE.includes(x.cause));
if (partial) return { level: l, state: 'NOT_MEASURED', rules: [], cause: partial.cause, reason: partial.reason };
if (a.passed.length) return { level: l, state: 'PASSED', rules: [], reason: a.passed.join('; ') };
const n = a.nm[0] || { cause: 'not-judged', reason: 'no verifier of this artifact judges this level' };
return { level: l, state: 'NOT_MEASURED', rules: [], cause: n.cause, reason: n.reason };
});
const failed = [...new Set(levels.flatMap((x) => x.rules))].sort();
const partial = levels.some((x) => x.state === 'NOT_MEASURED' && CAUZE_PARTIALE.includes(x.cause));
const verdict = failed.length ? 'INVALID' : partial || levels[0].state !== 'PASSED' ? 'PARTIAL' : 'VALID';
return { v: 1, kind: 'aere-conformance-verdict', artifact, verdict, levels, failed };
}