/** * FairnessReceipt — sovereign, replayable receipt for an algorithmic-fairness * evaluation, built on the SimulationContract hash + replay primitives WITHOUT * inheriting the physics-shaped provenance types. * * Why a sibling type and not `WorldModelReceipt` / `SimulationProvenance`: * those carry physics fields (geometryHash, solverType, scaleEnvelope, mesh * connectivity, JEPA latent vectors). Forcing credit / underwriting fairness * fields into them would pollute the physics provenance type and violate D.007 * (domain-free core). Instead this module reuses the *primitives*: * - the `hashBytes` chokepoint (FNV-1a default / SHA-256 opt-in, sha256.ts), * so a fairness receipt is hashed under the exact same SECURITY-mode wiring * as every physics contract hash site; and * - the Guarantee-6 replay discipline (rebuild identity from a record, * re-derive the fingerprint, flag MATCH/DRIFT on comparison). * * It carries only fairness-shaped fields and a versioned regulatory crosswalk * (data, not hardcoded behavior — the crosswalk ships as overridable constants). * * @see ../sha256 — the hashBytes / HashMode chokepoint this reuses * @see ./FairnessSweep — produces the metrics these receipts wrap */ import { type HashMode } from '../sha256'; import type { JurisdictionAuditSummary } from './JurisdictionConfig'; /** * Stable, key-sorted JSON serialization for content hashing. Recurses objects * (keys sorted) and arrays (order preserved). Non-finite numbers and * undefined/function values serialize to `null` so a hash never depends on * platform float formatting of NaN/Infinity. */ export declare function canonicalize(value: unknown): string; /** Content hash over any value via the SimulationContract hash chokepoint. */ export declare function hashContent(value: unknown, mode?: HashMode): string; /** * How reproducibly a model + pipeline re-executes — declared on the receipt so a * regulator knows exactly what re-execution they are getting, instead of a bare * (and on a real model often false) "byte-identical replay" claim: * - 'exact' — bit-reproducible decisions; `decisionDigest` re-runs byte-identical. * - 'quantized' — individual decisions may vary; the aggregate adverse-impact * ratio reproduces within `replayTolerance`. * - 'statistical' — only the distribution-level verdict is stable; pair with a * FairnessRobustnessReceipt band for verification. * The grade is declared by the model and MEASURED by the engine (double-run) — an * over-claimed 'exact' is auto-downgraded, never trusted (see runFairnessSweep). */ export type DeterminismGrade = 'exact' | 'quantized' | 'statistical'; /** * Content digest over an ordered boolean decision vector — the exact-grade replay * artifact. A validator re-running the model on the recorded inputs recomputes * this and compares; on an `exact` model it is byte-identical. */ export declare function computeDecisionDigest(decisions: readonly boolean[], mode?: HashMode): string; /** Disparity metrics a fairness/anti-discrimination examiner names directly. */ export interface FairnessMetrics { /** Per-group approval rate, keyed by protected-attribute value. */ approvalRate: Record; /** EEOC 4/5ths adverse-impact ratio: min(rate) / max(rate) across groups. */ adverseImpactRatio: number; /** Largest pairwise demographic-parity difference: max(rate) − min(rate). */ demographicParityDiff: number; /** adverseImpactRatio ≥ 0.80 (the 4/5ths threshold). */ fourFifthsPass: boolean; } /** * The inputs that uniquely determine a fairness decision. A validator who * re-runs the model from this key alone must re-derive the same * `replayFingerprint` — this is the offline-replay guarantee. */ export interface FairnessReplayKey { modelHash: string; seed: number; inputHash: string; weightStrategy: string; } export declare function computeReplayFingerprint(key: FairnessReplayKey, mode?: HashMode): string; export interface FairnessReceipt { kind: 'fairness.receipt.v1'; modelId: string; modelHash: string; seed: number; inputHash: string; weightStrategy: string; /** Hash over the replay key — re-derivable by a validator from the key alone. */ replayFingerprint: string; sampleSize: number; protectedAttribute: string; metrics: FairnessMetrics; decision: 'PASS' | 'FLAG-DISPARATE-IMPACT'; /** Content digest over the ordered per-record decisions (exact-grade replay artifact). */ decisionDigest: string; /** Content digest over the disparity metrics. */ metricsDigest: string; /** Declared + engine-measured reproducibility grade (see DeterminismGrade). */ replayDeterminism: DeterminismGrade; /** Max |Δ adverse-impact ratio| tolerated on replay (0 for 'exact'). */ replayTolerance: number; /** Versioned regulator crosswalk (data — overridable per engagement). */ regulatoryMapping: Record; /** Optional jurisdiction-specific test bundle and disclosure metadata. */ jurisdiction?: JurisdictionAuditSummary; hashMode: HashMode; issuedAt: string; /** Content hash over the whole receipt body (computed with this field omitted). */ receiptHash: string; } export interface EmitFairnessReceiptParams { modelId: string; modelHash: string; seed: number; inputHash: string; weightStrategy: string; sampleSize: number; protectedAttribute: string; metrics: FairnessMetrics; /** Digest over the ordered per-record decisions (from computeDecisionDigest). */ decisionDigest: string; /** Declared/measured reproducibility grade (default 'exact'). */ replayDeterminism?: DeterminismGrade; /** Replay tolerance for non-exact grades (default 0). */ replayTolerance?: number; regulatoryMapping?: Record; jurisdiction?: JurisdictionAuditSummary; issuedAt: string; hashMode?: HashMode; } export declare function emitFairnessReceipt(p: EmitFairnessReceiptParams): FairnessReceipt; export interface RobustnessBand { /** Ensemble mean adverse-impact ratio. */ mean: number; /** Ensemble standard deviation. */ std: number; /** 90% confidence interval on the adverse-impact ratio: [p5, p95]. */ ci90: [number, number]; /** Worst-case (minimum) adverse-impact ratio over the ensemble. */ worstCase: number; } export interface FairnessRobustnessReceipt { kind: 'fairness.robustness.v1'; modelId: string; modelHash: string; seed: number; baseInputHash: string; weightStrategy: string; replicates: number; replayFingerprint: string; /** Content hash over the sorted ensemble of adverse-impact ratios. */ ensembleHash: string; robustness: RobustnessBand; verdict: 'ROBUSTLY-FAIR' | 'ROBUSTLY-UNFAIR' | 'INDETERMINATE-FAIRNESS'; regulatoryMapping: Record; hashMode: HashMode; issuedAt: string; receiptHash: string; } export interface EmitRobustnessReceiptParams { modelId: string; modelHash: string; seed: number; baseInputHash: string; weightStrategy: string; replicates: number; ensembleHash: string; robustness: RobustnessBand; verdict: FairnessRobustnessReceipt['verdict']; regulatoryMapping?: Record; issuedAt: string; hashMode?: HashMode; } export declare function emitRobustnessReceipt(p: EmitRobustnessReceiptParams): FairnessRobustnessReceipt; export type ReplayVerdict = 'MATCH' | 'DRIFT'; /** * Integrity check: recompute the receipt's content hash and compare. Returns * true iff the receipt body is byte-identical to what was issued (catches any * post-hoc tamper of the receipt itself). */ export declare function verifyReceiptIntegrity(receipt: FairnessReceipt | FairnessRobustnessReceipt): boolean; /** * Offline replay (Guarantee 6): given an independently-observed replay key — * e.g. a validator who re-ran the model on the recorded inputs — return MATCH * iff the re-derived fingerprint equals the receipt's, else DRIFT. Any change * to model, seed, inputs, or weights breaks the fingerprint. */ export declare function replayFairnessReceipt(receipt: { replayFingerprint: string; hashMode: HashMode; }, observedKey: FairnessReplayKey): ReplayVerdict; /** * Re-execution verification — the determinism-aware Guarantee 6. Given a FRESH * re-run of the model on the recorded inputs, returns MATCH iff the re-run * reproduces the receipt to the grade the receipt declares: * - 'exact' → the decision digest must be byte-identical. * - 'quantized' / 'statistical'→ the re-run adverse-impact ratio must be within * `replayTolerance` of the recorded value. * This is what `replayFairnessReceipt` (input-key identity) cannot do alone: it * verifies OUTPUTS, so a non-deterministic model no longer DRIFTs spuriously. */ export declare function verifyReplayExecution(receipt: Pick, rerun: { decisionDigest: string; adverseImpactRatio: number; }): ReplayVerdict; /** * Per-decision receipt → regulator mapping. One receipt satisfies these * simultaneously. Ships as the verified default; pass a custom map to * `emitFairnessReceipt` to version it per jurisdiction. */ export declare const DEFAULT_FAIRNESS_CROSSWALK: Record; /** Robustness receipt → regulator mapping (stress-scenario / drift-monitoring asks). */ export declare const DEFAULT_ROBUSTNESS_CROSSWALK: Record; //# sourceMappingURL=FairnessReceipt.d.ts.map