Scaffold dd0c/cost: Welford baseline, anomaly scorer, governance engine, tests
- Welford online algorithm for running mean/stddev baselines - Anomaly scorer: z-score → 0-100 mapping, property-based tests (10K runs, fast-check) - Governance engine: 14-day auto-promotion with FP rate gate, injectable Clock - Panic mode: defaults to active (safe) when Redis unreachable - Tests: 12 scorer cases (incl 2x 10K property-based), 9 governance cases, 3 panic mode cases - PostgreSQL schema with RLS: baselines (optimistic locking), anomalies, remediation_actions - Fly.io config, Dockerfile
This commit is contained in:
72
products/05-aws-cost-anomaly/tests/unit/governance.test.ts
Normal file
72
products/05-aws-cost-anomaly/tests/unit/governance.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { GovernanceEngine, FakeClock } from '../../src/governance/engine.js';
|
||||
|
||||
describe('GovernanceEngine', () => {
|
||||
let clock: FakeClock;
|
||||
let engine: GovernanceEngine;
|
||||
|
||||
beforeEach(() => {
|
||||
clock = new FakeClock(new Date('2026-03-01').getTime());
|
||||
engine = new GovernanceEngine(clock);
|
||||
});
|
||||
|
||||
it('does not promote at day 13', () => {
|
||||
const result = engine.evaluatePromotion('t1', { fpRate: 0.05, daysInCurrentMode: 13 });
|
||||
expect(result.promoted).toBe(false);
|
||||
});
|
||||
|
||||
it('promotes at day 15 with low FP rate', () => {
|
||||
const result = engine.evaluatePromotion('t1', { fpRate: 0.05, daysInCurrentMode: 15 });
|
||||
expect(result.promoted).toBe(true);
|
||||
expect(result.newMode).toBe('audit');
|
||||
});
|
||||
|
||||
it('does not promote at day 15 with high FP rate', () => {
|
||||
const result = engine.evaluatePromotion('t1', { fpRate: 0.15, daysInCurrentMode: 15 });
|
||||
expect(result.promoted).toBe(false);
|
||||
expect(result.reason).toContain('false-positive rate');
|
||||
});
|
||||
|
||||
it('promotes at exactly day 14 with 0% FP rate', () => {
|
||||
const result = engine.evaluatePromotion('t1', { fpRate: 0, daysInCurrentMode: 14 });
|
||||
expect(result.promoted).toBe(true);
|
||||
});
|
||||
|
||||
it('does not promote at exactly 10% FP rate', () => {
|
||||
const result = engine.evaluatePromotion('t1', { fpRate: 0.10, daysInCurrentMode: 20 });
|
||||
expect(result.promoted).toBe(true); // 10% is the threshold, not exceeded
|
||||
});
|
||||
|
||||
it('does not promote at 10.1% FP rate', () => {
|
||||
const result = engine.evaluatePromotion('t1', { fpRate: 0.101, daysInCurrentMode: 20 });
|
||||
expect(result.promoted).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Panic Mode Redis Failure', () => {
|
||||
let engine: GovernanceEngine;
|
||||
|
||||
beforeEach(() => {
|
||||
engine = new GovernanceEngine();
|
||||
});
|
||||
|
||||
it('defaults to panic=active when Redis is unreachable', async () => {
|
||||
const fakeRedis = {
|
||||
get: async () => { throw new Error('Connection refused'); },
|
||||
};
|
||||
const result = await engine.checkPanicMode('t1', fakeRedis);
|
||||
expect(result).toBe(true); // Safe default
|
||||
});
|
||||
|
||||
it('returns false when panic is not set', async () => {
|
||||
const fakeRedis = { get: async () => null };
|
||||
const result = await engine.checkPanicMode('t1', fakeRedis);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('returns true when panic is active', async () => {
|
||||
const fakeRedis = { get: async () => '1' };
|
||||
const result = await engine.checkPanicMode('t1', fakeRedis);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user