Spaces:
Running
Running
File size: 5,301 Bytes
518343a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | // SPDX-License-Identifier: Apache-2.0
// © 2026 Lutar, Stephen P. — SZL Holdings
// ORCID: 0009-0001-0110-4173
//
// Layer 6 — a11oy policy gate for AdversarialRobustness
//
// Policy rationale:
// A composed pipeline is allowed to deploy only when the end-to-end
// adversarial output perturbation bound ε₂ = L₁·L₂·δ is at or below the
// configured maximum tolerable perturbation. The Lean theorem proves that
// if each component is (δ,ε)-robust, the composition is (δ,ε₂)-robust.
// This gate enforces that the composed system does not amplify adversarial
// inputs beyond the policy tolerance.
//
// Lean theorem cited: `robustness_preserved_by_composition`
// Lean file: Lutar/Composition/AdversarialRobustness.lean
// Lean commit SHA: 1dca00032dfc9aa8559cc6c2e4b63192fcf52371
//
// Policy: if adversarialRobustness(opts).epsilon2 ≤ maxEpsilon → allow; else → deny
//
// References:
// Lean: szl-holdings/lutar-lean Lutar/Composition/AdversarialRobustness.lean
// Runtime: szl-holdings/ouroboros agentic/formulas/adversarialRobustness.ts
// Madry et al. 2018, arXiv:1706.06083
export interface PolicyDecision {
allow: boolean;
rationale: string;
formula: string;
leanTheorem: string;
leanFile: string;
leanCommitSha: string;
epsilon2: number;
composedLipschitz: number;
maxEpsilon: number;
lambdaScore: number;
}
export interface AdversarialRobustnessGateConfig {
/**
* Maximum tolerable ε₂ (end-to-end output perturbation).
* Default: 1.0 (unit ball tolerance).
*/
maxEpsilon?: number;
}
export interface AdversarialRobustnessGateOpts {
lipschitz1: number;
lipschitz2: number;
delta: number;
}
const LEAN_THEOREM = "robustness_preserved_by_composition";
const LEAN_FILE = "Lutar/Composition/AdversarialRobustness.lean";
const LEAN_COMMIT = "1dca00032dfc9aa8559cc6c2e4b63192fcf52371";
const DEFAULT_EPS = 1.0;
// ── Inline formula ────────────────────────────────────────────────────────────
// Lean: robustness_preserved_by_composition:
// IsRobust mX mY f δ ε₁ → IsRobust mY mZ g ε₁ ε₂ → IsRobust mX mZ (f∘g) δ ε₂
//
// Note (PhD audit 2026-05-29): the Lean theorem is stated for abstract metric
// spaces and does not require Lipschitz structure. This gate computes the
// Lipschitz special case: if S₁ has Lipschitz constant L₁, then ε₁ = L₁·δ; if
// S₂ has Lipschitz constant L₂, then ε₂ = L₂·ε₁ = L₁·L₂·δ. Consumers that need
// non-Lipschitz robustness certificates should instantiate the Lean theorem
// directly with their metric model rather than treating this numeric gate as
// the full theorem.
function _composedEpsilon(l1: number, l2: number, delta: number): { epsilon2: number; composedLipschitz: number } {
return { epsilon2: l1 * l2 * delta, composedLipschitz: l1 * l2 };
}
/**
* AdversarialRobustness policy gate.
*
* Allows pipeline deployment only when the composed adversarial output
* perturbation bound ε₂ ≤ maxEpsilon.
*
* Lean theorem: `robustness_preserved_by_composition`
* Lean file: Lutar/Composition/AdversarialRobustness.lean (commit 1dca00032dfc9aa8559cc6c2e4b63192fcf52371)
*/
export function adversarialRobustnessGate(
config: AdversarialRobustnessGateConfig = {}
): (opts: AdversarialRobustnessGateOpts) => PolicyDecision {
const maxEpsilon = config.maxEpsilon ?? DEFAULT_EPS;
if (!Number.isFinite(maxEpsilon) || maxEpsilon < 0) {
throw new Error(`AdversarialRobustnessGate: maxEpsilon must be ≥ 0; got ${maxEpsilon}`);
}
return function gate(opts: AdversarialRobustnessGateOpts): PolicyDecision {
const { lipschitz1, lipschitz2, delta } = opts;
if (lipschitz1 <= 0 || !Number.isFinite(lipschitz1)) {
throw new Error(`AdversarialRobustnessGate: lipschitz1 must be > 0; got ${lipschitz1}`);
}
if (lipschitz2 <= 0 || !Number.isFinite(lipschitz2)) {
throw new Error(`AdversarialRobustnessGate: lipschitz2 must be > 0; got ${lipschitz2}`);
}
if (delta <= 0 || !Number.isFinite(delta)) {
throw new Error(`AdversarialRobustnessGate: delta must be > 0; got ${delta}`);
}
const { epsilon2, composedLipschitz } = _composedEpsilon(lipschitz1, lipschitz2, delta);
const lambdaScore = 1 / (1 + epsilon2);
const allow = epsilon2 <= maxEpsilon;
const rationale = allow
? `AdversarialRobustness ε₂ = ${epsilon2.toExponential(4)} ≤ maxEpsilon ${maxEpsilon}: ` +
`composed pipeline is (${delta},${epsilon2})-robust. Lean: ${LEAN_THEOREM} @${LEAN_COMMIT.slice(0, 12)}`
: `AdversarialRobustness ε₂ = ${epsilon2.toExponential(4)} > maxEpsilon ${maxEpsilon}: ` +
`perturbation amplification exceeds policy tolerance — deny deployment. Lean: ${LEAN_THEOREM} @${LEAN_COMMIT.slice(0, 12)}`;
return {
allow,
rationale,
formula: "AdversarialRobustness",
leanTheorem: LEAN_THEOREM,
leanFile: LEAN_FILE,
leanCommitSha: LEAN_COMMIT,
epsilon2,
composedLipschitz,
maxEpsilon,
lambdaScore,
};
};
}
|