const ROLLING_WINDOW = 50; const CONSECUTIVE_LIMIT = 3; const ROLLING_DENIAL_LIMIT = 10; export class DenialCircuitBreaker { private consecutiveDenials = 0; private readonly recent: boolean[] = []; private tripped = false; resetTurn(): void { this.consecutiveDenials = 0; this.recent.length = 0; this.tripped = false; } recordExplicitDenial(): boolean { this.consecutiveDenials += 1; this.push(true); if (!this.tripped && (this.consecutiveDenials >= CONSECUTIVE_LIMIT || this.denialCount() >= ROLLING_DENIAL_LIMIT)) { this.tripped = true; return true; } return false; } /** Allows and failed-closed outcomes are both non-denials for the Codex-compatible breaker. */ recordNonDenial(): void { this.consecutiveDenials = 0; this.push(false); } isTripped(): boolean { return this.tripped; } private push(denied: boolean): void { this.recent.push(denied); if (this.recent.length > ROLLING_WINDOW) this.recent.shift(); } private denialCount(): number { return this.recent.filter(Boolean).length; } }