Reference implementation for the Phoenix Architecture. Work in progress.
aicoding.leaflet.pub/
ai
coding
crazy
1/**
2 * Policy Engine — evaluates whether an IU has sufficient evidence.
3 *
4 * Each risk tier requires specific evidence kinds. The engine checks
5 * what's been collected and what's missing or failing.
6 */
7
8import type { ImplementationUnit } from './models/iu.js';
9import type { EvidenceRecord, PolicyEvaluation } from './models/evidence.js';
10import { EvidenceStatus } from './models/evidence.js';
11
12/**
13 * Evaluate an IU's evidence against its policy.
14 */
15export function evaluatePolicy(
16 iu: ImplementationUnit,
17 evidence: EvidenceRecord[],
18): PolicyEvaluation {
19 const required = iu.evidence_policy.required;
20 const iuEvidence = evidence.filter(e => e.iu_id === iu.iu_id);
21
22 const satisfied: string[] = [];
23 const missing: string[] = [];
24 const failed: string[] = [];
25
26 for (const req of required) {
27 const matching = iuEvidence.filter(e => e.kind === req);
28 if (matching.length === 0) {
29 missing.push(req);
30 } else {
31 const latest = matching[matching.length - 1];
32 if (latest.status === EvidenceStatus.PASS) {
33 satisfied.push(req);
34 } else if (latest.status === EvidenceStatus.FAIL) {
35 failed.push(req);
36 } else {
37 missing.push(req); // PENDING or SKIPPED count as missing
38 }
39 }
40 }
41
42 let verdict: 'PASS' | 'FAIL' | 'INCOMPLETE';
43 if (failed.length > 0) {
44 verdict = 'FAIL';
45 } else if (missing.length > 0) {
46 verdict = 'INCOMPLETE';
47 } else {
48 verdict = 'PASS';
49 }
50
51 return {
52 iu_id: iu.iu_id,
53 iu_name: iu.name,
54 risk_tier: iu.risk_tier,
55 required,
56 satisfied,
57 missing,
58 failed,
59 verdict,
60 };
61}
62
63/**
64 * Evaluate policy for all IUs.
65 */
66export function evaluateAllPolicies(
67 ius: ImplementationUnit[],
68 evidence: EvidenceRecord[],
69): PolicyEvaluation[] {
70 return ius.map(iu => evaluatePolicy(iu, evidence));
71}