a11oy / packages /policy /src /gates /singleWitnessExclusion_gate.ts
betterwithage's picture
sync(space): complete build context — fix BUILD_ERROR (CTO)
518343a verified
Raw
History Blame
3.11 kB
// SPDX-License-Identifier: Apache-2.0
// © 2026 Lutar, Stephen P. — SZL Holdings
// ORCID: 0009-0001-0110-4173
//
// Layer 6 — a11oy policy gate for SingleWitnessExclusion (T8)
//
// Policy rationale:
// Different actors with identical digest content produce different SHA-256
// receipt hashes (different canonical JSON → different hash). Single-witness
// closure fails for cross-actor pairs. This gate enforces T8: dual witness
// is required whenever actor IDs differ.
//
// Lean derivation cited: `singleWitnessExclusion` (T8)
// Lean file: Lutar/Gate/SingleWitnessExclusion.lean
// Lean commit SHA: 1dca00032dfc9aa8559cc6c2e4b63192fcf52371
// Lean status: theorem (ENFORCED)
//
// References:
// Zenodo: https://doi.org/10.5281/zenodo.20119582
// INNOVATIONS.md §2 T8: single-witness exclusion
export interface SingleWitnessExclusionGateConfig {
/** If false, same-actor single-witness is allowed. Default: true (require dual). */
requireDualForSameActor?: boolean;
}
export interface SingleWitnessExclusionGateOpts {
actor1Id: string;
actor2Id: string;
witnessCount: number;
}
export interface SingleWitnessExclusionDecision {
allow: boolean;
rationale: string;
formula: string;
leanTheorem: string;
leanFile: string;
leanCommitSha: string;
sameActor: boolean;
witnessCount: number;
dualRequired: boolean;
lambdaScore: number;
}
const LEAN_THEOREM = "singleWitnessExclusion";
const LEAN_FILE = "Lutar/Gate/SingleWitnessExclusion.lean";
const LEAN_COMMIT = "1dca00032dfc9aa8559cc6c2e4b63192fcf52371";
export function singleWitnessExclusionGate(
config: SingleWitnessExclusionGateConfig = {}
): (opts: SingleWitnessExclusionGateOpts) => SingleWitnessExclusionDecision {
const requireDualForSameActor = config.requireDualForSameActor ?? true;
return function gate(opts: SingleWitnessExclusionGateOpts): SingleWitnessExclusionDecision {
const { actor1Id, actor2Id, witnessCount } = opts;
if (!actor1Id || !actor2Id) throw new Error(`SingleWitnessExclusionGate: actor IDs required`);
if (!Number.isInteger(witnessCount) || witnessCount < 0) {
throw new Error(`SingleWitnessExclusionGate: witnessCount must be non-negative integer`);
}
const sameActor = actor1Id === actor2Id;
const dualRequired = !sameActor || requireDualForSameActor;
const allow = !dualRequired || witnessCount >= 2;
const lambdaScore = allow ? 1.0 : witnessCount / 2;
const rationale = allow
? `SingleWitnessExclusion (T8): actors=${sameActor ? 'same' : 'different'}; witnesses=${witnessCount} ≥ ${dualRequired ? 2 : 1}. Passes. Lean: ${LEAN_THEOREM} @${LEAN_COMMIT.slice(0, 12)}`
: `SingleWitnessExclusion (T8): different actors require dual-witness; got ${witnessCount}. Denied. Lean: ${LEAN_THEOREM} @${LEAN_COMMIT.slice(0, 12)}`;
return { allow, rationale, formula: "SingleWitnessExclusion", leanTheorem: LEAN_THEOREM, leanFile: LEAN_FILE, leanCommitSha: LEAN_COMMIT, sameActor, witnessCount, dualRequired, lambdaScore };
};
}