nx_cgmp_test.nx source
↩ module page · 192 lines · 9649 B
1// nx_cgmp_test.nx -- gate for the 21 CFR 111 cGMP readiness checklist.
2// T3 is the discipline the whole organ exists for: a facility missing ONE
3// critical requirement is NOT audit-ready no matter how many minors it has,
4// and the gap reported is the worst one, worst-first.
5// expect_exit: 0 license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_cgmp.nx"
8
9func t_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
10func t_putn(v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) } let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0 }
11
12func main() -> i64 {
13 var pass: i64 = 0
14 var total: i64 = 0
15
16 // --- T1 a fully-compliant facility is audit-ready, score 1000, 0 gaps ---
17 total = total + 1
18 let full: *NxCgmpState = nx_cgmp_new()
19 cg_set_all(full)
20 let ready: i64 = cg_audit_ready(full)
21 let score: i64 = cg_readiness_permil(full)
22 let gaps: i64 = cg_total_gaps(full)
23 let cgap: i64 = cg_first_critical_gap(full)
24 t_puts("T1 full facility: audit_ready=" as *u8); t_putn(ready); t_puts(" score=" as *u8); t_putn(score); t_puts(" gaps=" as *u8); t_putn(gaps); t_puts(" first_critical=" as *u8); t_putn(cgap); t_puts(" want 1/1000/0/-1: " as *u8)
25 var ok1: i64 = 1
26 if ready != 1 { ok1 = 0 }
27 if score != 1000 { ok1 = 0 }
28 if gaps != 0 { ok1 = 0 }
29 if cgap != 0 - 1 { ok1 = 0 }
30 if ok1 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
31
32 // --- T2 an empty facility: not ready, first critical gap = specs (id 0) ---
33 total = total + 1
34 let empty: *NxCgmpState = nx_cgmp_new()
35 let e_ready: i64 = cg_audit_ready(empty)
36 let e_gap: i64 = cg_first_critical_gap(empty)
37 let e_cgaps: i64 = cg_critical_gaps(empty)
38 t_puts("T2 empty facility: audit_ready=" as *u8); t_putn(e_ready); t_puts(" first_critical_gap=" as *u8); t_putn(e_gap); t_puts(" (" as *u8); t_puts(cg_citation(e_gap)); t_puts(") critical_gaps=" as *u8); t_putn(e_cgaps); t_puts(": " as *u8)
39 var ok2: i64 = 1
40 if e_ready != 0 { ok2 = 0 }
41 if e_gap != CG_SPECIFICATIONS { ok2 = 0 }
42 if e_cgaps != 6 { ok2 = 0 }
43 if ok2 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
44
45 // --- T3 THE DISCIPLINE: every MINOR met but ONE critical open =>
46 // still NOT audit-ready, and the gap is that critical one ---
47 total = total + 1
48 let mixed: *NxCgmpState = nx_cgmp_new()
49 cg_set_all(mixed)
50 // now "un-meet" one critical: the batch production record. (No un-set fn;
51 // rebuild the mask without BPR by setting all EXCEPT BPR.)
52 let m2: *NxCgmpState = nx_cgmp_new()
53 var i3: i64 = 0
54 while i3 < CG_N {
55 if i3 != CG_BPR { cg_set_met(m2, i3) }
56 i3 = i3 + 1
57 }
58 let m_ready: i64 = cg_audit_ready(m2)
59 let m_gap: i64 = cg_first_critical_gap(m2)
60 let m_score: i64 = cg_readiness_permil(m2)
61 t_puts("T3 all-but-BPR: audit_ready=" as *u8); t_putn(m_ready); t_puts(" gap=" as *u8); t_putn(m_gap); t_puts(" (BPR=5) score=" as *u8); t_putn(m_score); t_puts(" (high but NOT ready): " as *u8)
62 var ok3: i64 = 1
63 if m_ready != 0 { ok3 = 0 }
64 if m_gap != CG_BPR { ok3 = 0 }
65 if m_score < 900 { ok3 = 0 }
66 if ok3 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
67
68 // --- T4 critical gaps are reported WORST-FIRST (id order over criticals) ---
69 // Meet specs; the next critical gap must be identity testing (id 1), not
70 // some later critical.
71 total = total + 1
72 let step: *NxCgmpState = nx_cgmp_new()
73 cg_set_met(step, CG_SPECIFICATIONS)
74 let s_gap: i64 = cg_first_critical_gap(step)
75 cg_set_met(step, CG_ID_TESTING)
76 let s_gap2: i64 = cg_first_critical_gap(step)
77 t_puts("T4 after specs: next critical=" as *u8); t_putn(s_gap); t_puts(" (ID_TESTING=1) ; after +id-testing: " as *u8); t_putn(s_gap2); t_puts(" (FINISHED=3): " as *u8)
78 var ok4: i64 = 1
79 if s_gap != CG_ID_TESTING { ok4 = 0 }
80 if s_gap2 != CG_FINISHED_TESTING { ok4 = 0 }
81 if ok4 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
82
83 // --- T5 the CRITICAL set is exactly the 6 warning-letter requirements ---
84 total = total + 1
85 var i5: i64 = 0
86 var ncrit: i64 = 0
87 while i5 < CG_N {
88 if cg_criticality(i5) == CG_CRITICAL { ncrit = ncrit + 1 }
89 i5 = i5 + 1
90 }
91 let c_spec: i64 = cg_criticality(CG_SPECIFICATIONS)
92 let c_id: i64 = cg_criticality(CG_ID_TESTING)
93 let c_qc: i64 = cg_criticality(CG_QC_UNIT)
94 let c_comp: i64 = cg_criticality(CG_COMPLAINTS)
95 t_puts("T5 critical count=" as *u8); t_putn(ncrit); t_puts(" (specs/id/qc CRITICAL=" as *u8); t_putn(c_spec); t_putn(c_id); t_putn(c_qc); t_puts(" complaints MINOR=" as *u8); t_putn(c_comp); t_puts("): " as *u8)
96 var ok5: i64 = 1
97 if ncrit != 6 { ok5 = 0 }
98 if c_spec != CG_CRITICAL { ok5 = 0 }
99 if c_id != CG_CRITICAL { ok5 = 0 }
100 if c_qc != CG_CRITICAL { ok5 = 0 }
101 if c_comp != CG_MINOR { ok5 = 0 }
102 if ok5 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
103
104 // --- T6 weighted score reflects CRITICALITY, not a raw count ---
105 // Meeting the 6 criticals (weight 3 each = 18) is worth more than meeting
106 // the 2 minors (weight 1 each = 2), though 6 vs 2 by count.
107 total = total + 1
108 let crit_only: *NxCgmpState = nx_cgmp_new()
109 var i6: i64 = 0
110 while i6 < CG_N {
111 if cg_criticality(i6) == CG_CRITICAL { cg_set_met(crit_only, i6) }
112 i6 = i6 + 1
113 }
114 let minor_only: *NxCgmpState = nx_cgmp_new()
115 var i6b: i64 = 0
116 while i6b < CG_N {
117 if cg_criticality(i6b) == CG_MINOR { cg_set_met(minor_only, i6b) }
118 i6b = i6b + 1
119 }
120 let crit_score: i64 = cg_readiness_permil(crit_only)
121 let minor_score: i64 = cg_readiness_permil(minor_only)
122 t_puts("T6 criticals-only score=" as *u8); t_putn(crit_score); t_puts(" minors-only score=" as *u8); t_putn(minor_score); t_puts(" (criticals worth far more): " as *u8)
123 if crit_score > minor_score { if crit_score > 500 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) } } else { t_puts("FAIL\n" as *u8) }
124
125 // --- T7 the IDENTITY dimension maps to specs + 100% id testing ---
126 // This is the bridge that lets the plan DERIVE identity_ready.
127 total = total + 1
128 let idst: *NxCgmpState = nx_cgmp_new()
129 let id_none: i64 = cg_identity_dimension_met(idst)
130 cg_set_met(idst, CG_SPECIFICATIONS)
131 let id_half: i64 = cg_identity_dimension_met(idst)
132 cg_set_met(idst, CG_ID_TESTING)
133 let id_full: i64 = cg_identity_dimension_met(idst)
134 t_puts("T7 identity dim: none=" as *u8); t_putn(id_none); t_puts(" specs-only=" as *u8); t_putn(id_half); t_puts(" specs+id=" as *u8); t_putn(id_full); t_puts(" want 0/0/1: " as *u8)
135 var ok7: i64 = 1
136 if id_none != 0 { ok7 = 0 }
137 if id_half != 0 { ok7 = 0 }
138 if id_full != 1 { ok7 = 0 }
139 if ok7 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
140
141 // --- T8 fail-closed on bad ids + bitmask round-trip ---
142 total = total + 1
143 let s8: *NxCgmpState = nx_cgmp_new()
144 let bad_set: i64 = cg_set_met(s8, 99)
145 let bad_met: i64 = cg_is_met(s8, 99)
146 cg_set_met(s8, CG_MMR)
147 let mmr_met: i64 = cg_is_met(s8, CG_MMR)
148 let bpr_met: i64 = cg_is_met(s8, CG_BPR)
149 t_puts("T8 bad-id set=" as *u8); t_putn(bad_set); t_puts(" bad-id met=" as *u8); t_putn(bad_met); t_puts(" MMR-met=" as *u8); t_putn(mmr_met); t_puts(" BPR-absent=" as *u8); t_putn(bpr_met); t_puts(": " as *u8)
150 var ok8: i64 = 1
151 if bad_set != 0 { ok8 = 0 }
152 if bad_met != 0 { ok8 = 0 }
153 if mmr_met != 1 { ok8 = 0 }
154 if bpr_met != 0 { ok8 = 0 }
155 if ok8 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
156
157 // --- T9 every requirement has a name + a real 21 CFR citation ---
158 total = total + 1
159 var i9: i64 = 0
160 var ok9: i64 = 1
161 while i9 < CG_N {
162 let nm: *u8 = cg_name(i9)
163 let ci: *u8 = cg_citation(i9)
164 if nm[0] == (0 as u8) { ok9 = 0 }
165 // citation must start with "21 CFR"
166 if ci[0] != (50 as u8) { ok9 = 0 }
167 if cg_criticality(i9) < CG_MINOR { ok9 = 0 }
168 i9 = i9 + 1
169 }
170 t_puts("T9 all " as *u8); t_putn(CG_N); t_puts(" requirements carry a name + 21 CFR citation + criticality: " as *u8)
171 if ok9 == 1 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) }
172
173 // --- T10 readiness climbs monotonically as requirements are met ---
174 total = total + 1
175 let climb: *NxCgmpState = nx_cgmp_new()
176 var prev: i64 = 0 - 1
177 var i10: i64 = 0
178 var ok10: i64 = 1
179 while i10 < CG_N {
180 cg_set_met(climb, i10)
181 let sc: i64 = cg_readiness_permil(climb)
182 if sc < prev { ok10 = 0 }
183 prev = sc
184 i10 = i10 + 1
185 }
186 t_puts("T10 readiness monotonically non-decreasing as requirements met, ends " as *u8); t_putn(prev); t_puts(": " as *u8)
187 if ok10 == 1 { if prev == 1000 { pass = pass + 1; t_puts("PASS\n" as *u8) } else { t_puts("FAIL\n" as *u8) } } else { t_puts("FAIL\n" as *u8) }
188
189 t_puts("CGMP-GATE passed " as *u8); t_putn(pass); t_puts("/" as *u8); t_putn(total)
190 if pass == total { t_puts(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
191 t_puts(" verdict=RED\n" as *u8); sys_exit(1); return 1
192}