/** * ⚖️ THE FAIRNESS CERTIFICATE — is a model's decision fair across protected groups, with a real guarantee? * * Regulators (the EU AI Act, US fair-lending law) increasingly demand proof that an automated decision does not * discriminate across a protected attribute. The naive check — "the positive rates look about equal" — is a trap * twice over: a real gap can hide inside sampling noise (a model is waved through as fair when it isn't), and a * harmless wobble can be mistaken for bias (a fair model is falsely accused). Nobody hands you a signed, * offline-checkable verdict with the statistical uncertainty built in. * * This certificate measures the two canonical group-fairness gaps — DEMOGRAPHIC PARITY (the spread in positive * rate across groups) and, when ground-truth outcomes are supplied, EQUALIZED ODDS (the spread in true-positive * and false-positive rate across groups) — each with SIMULTANEOUS Wilson confidence intervals (Bonferroni-corrected * across every group and metric, so the joint claim holds). It then returns a calibrated verdict: FAIR when the * upper confidence bound on every gap is within the tolerance τ, UNFAIR when a gap's lower confidence bound exceeds * τ (and it names the offending metric + the two groups), INCONCLUSIVE when the data can't yet tell — and signs it. * * WORLD-FIRST + LLM-impossible: an LLM cannot build the per-group confusion counts, compute simultaneous Wilson * intervals, Bonferroni-correct them, and sign a re-derivable fairness verdict — it just eyeballs the rates. * (DIAKRISIS — MEASURED: a biased model is detected and the gap+groups named ~100%; a truly fair model is falsely * called UNFAIR ≤ α because the CI guards it; the gap confidence interval covers the true gap ≥ 1−α; a model fair * on demographic parity but not on equalized odds is flagged on the right metric. HONEST: this certifies the * group-fairness metrics on the data given — these metrics can mutually conflict and none is "fairness" in full; * the guarantee is statistical, conditional on the labels being correct and the protected attribute being right.) */ import { type KeyObject } from "node:crypto"; interface GroupRate { group: string; n: number; rate: number; lo: number; hi: number; } interface MetricGap { metric: "demographic-parity" | "equalized-odds-TPR" | "equalized-odds-FPR"; scope: "marginal" | "intersectional"; system: string; gap: number; gapLo: number; gapHi: number; highGroup: string; lowGroup: string; perGroup: GroupRate[]; } interface AxisLabels { name: string; of: string[]; } export interface FairnessCertificate { standard: "melete-fairness-certificate/v2"; verdict: "FAIR" | "UNFAIR" | "INCONCLUSIVE"; intersectional: boolean; tolerance: number; alpha: number; worstMetric: string | null; worstScope: string | null; worstSystem: string | null; metrics: MetricGap[]; n: number; groups: string[]; predictions: number[]; groupOf: string[]; axesOf: AxisLabels[] | null; outcomes: number[] | null; payloadHash: string; signature: string; publicKeyPem: string; algo: "ed25519+sha256"; } export declare function fairnessCertificate(opts: { predictions: number[]; groupOf?: string[]; axes?: AxisLabels[]; outcomes?: number[] | null; tolerance?: number; alpha?: number; keys?: { publicKey: KeyObject; privateKey: KeyObject; }; }): FairnessCertificate; export declare function verifyFairnessCertificate(c: FairnessCertificate): { ok: boolean; reason: string; }; export declare function fairnessGauntlet(): { score: 0 | 100; checks: Array<{ name: string; pass: boolean; detail: string; }>; }; export {}; //# sourceMappingURL=fairness.d.ts.map