code wiki / (root) / nx_cgmp.nx

nx_cgmp.nx source

↩ module page · 236 lines · 9428 B

1// nx_cgmp.nx -- GTM SUITE / 21 CFR 111 cGMP READINESS rung. Deepens the 2// plan engine's coarse "manufacturing / identity" attestations into the real 3// sub-part checklist a dietary-supplement contract manufacturer is audited 4// against -- so the plan can say not "qualify a cGMP facility" but exactly 5// which requirements are missing, worst-first. 6// 7// THE ORDERING IS BY WHAT DRAWS A WARNING LETTER. FDA 483 observations and 8// warning letters cluster on a knowable few requirements: no established 9// specifications, no 100% identity testing of incoming components, no master 10// manufacturing record, no batch record, no quality-control unit. Those are 11// tagged CRITICAL and a facility is not audit-ready while any is open -- 12// cgmp_first_critical_gap returns the worst one first, the same kill-order 13// discipline as the production-readiness engine it feeds. 14// 15// EVERY REQUIREMENT IS AN OPERATOR ATTESTATION, HONESTLY. This organ cannot 16// inspect a plant; it tracks which requirements are DECLARED met and scores 17// the gap, weighting CRITICAL > MAJOR > MINOR. It replaces a single yes/no 18// "gmp_qualified" flag with an actionable breakdown, not with a pretense of 19// having audited anything. 20// 21// THE CITATIONS ARE REAL so a plan line points at the actual regulation. 22// 23// Grounding (cited; researcher-groundable): 24// fda_21cfr111_current_good_manufacturing_practice_dietary_supplements 25// 111_70_specifications · 111_75_component_identity_testing 26// 111_205_master_manufacturing_record · 111_255_batch_production_record 27// 111_65_quality_control_operations · fda_483_warning_letter_cgmp_patterns 28// 29// genealogy_id: supplement_gtm + service_infrastructure 30 31import "nx_syscalls.nx" 32 33// ===== Criticality (sealed) =========================================== 34 35const CG_MINOR: i64 = 1 36const CG_MAJOR: i64 = 2 37const CG_CRITICAL: i64 = 3 38 39// ===== The 21 CFR 111 requirement catalog ============================= 40 41const CG_SPECIFICATIONS: i64 = 0 // 111.70 established specs 42const CG_ID_TESTING: i64 = 1 // 111.75(a)(1)(i) 100% component identity 43const CG_SUPPLIER_QUAL: i64 = 2 // 111.75(a)(2) supplier qualification 44const CG_FINISHED_TESTING: i64 = 3 // 111.75(c) finished-product to spec 45const CG_MMR: i64 = 4 // 111.205 master manufacturing record 46const CG_BPR: i64 = 5 // 111.255 batch production record 47const CG_QC_UNIT: i64 = 6 // 111.65 quality-control operations 48const CG_RESERVE_SAMPLES: i64 = 7 // 111.83 reserve samples 49const CG_TRAINED_PERSONNEL: i64 = 8 // 111.13 trained personnel 50const CG_SANITARY_PLANT: i64 = 9 // 111.15 sanitary physical plant 51const CG_CALIBRATED_EQUIP: i64 = 10 // 111.27 calibrated equipment 52const CG_LAB_CONTROLS: i64 = 11 // 111.320 laboratory controls 53const CG_COMPLAINTS: i64 = 12 // 111.560 product complaint handling 54const CG_RECORDS: i64 = 13 // 111.605 records retention 55const CG_N: i64 = 14 56 57func cg_valid(id: i64) -> i64 { 58 if id < 0 { return 0 } 59 if id >= CG_N { return 0 } 60 return 1 61} 62 63func cg_name(id: i64) -> *u8 { 64 if id == CG_SPECIFICATIONS { return "established specifications (identity/purity/strength/composition)" as *u8 } 65 if id == CG_ID_TESTING { return "100% identity testing of each incoming dietary ingredient" as *u8 } 66 if id == CG_SUPPLIER_QUAL { return "supplier qualification for other components" as *u8 } 67 if id == CG_FINISHED_TESTING { return "finished-product testing against specification" as *u8 } 68 if id == CG_MMR { return "master manufacturing record (MMR)" as *u8 } 69 if id == CG_BPR { return "batch production record (BPR) per batch" as *u8 } 70 if id == CG_QC_UNIT { return "quality-control unit with approval/reject authority" as *u8 } 71 if id == CG_RESERVE_SAMPLES { return "reserve samples of each batch" as *u8 } 72 if id == CG_TRAINED_PERSONNEL { return "trained, qualified personnel" as *u8 } 73 if id == CG_SANITARY_PLANT { return "sanitary physical plant + pest control" as *u8 } 74 if id == CG_CALIBRATED_EQUIP { return "calibrated, maintained equipment" as *u8 } 75 if id == CG_LAB_CONTROLS { return "laboratory controls + scientifically valid methods" as *u8 } 76 if id == CG_COMPLAINTS { return "product complaint handling procedure" as *u8 } 77 if id == CG_RECORDS { return "records retained >= 1 yr past shelf life + 2 yr" as *u8 } 78 return "unknown requirement" as *u8 79} 80 81func cg_citation(id: i64) -> *u8 { 82 if id == CG_SPECIFICATIONS { return "21 CFR 111.70" as *u8 } 83 if id == CG_ID_TESTING { return "21 CFR 111.75(a)(1)(i)" as *u8 } 84 if id == CG_SUPPLIER_QUAL { return "21 CFR 111.75(a)(2)" as *u8 } 85 if id == CG_FINISHED_TESTING { return "21 CFR 111.75(c)" as *u8 } 86 if id == CG_MMR { return "21 CFR 111.205" as *u8 } 87 if id == CG_BPR { return "21 CFR 111.255" as *u8 } 88 if id == CG_QC_UNIT { return "21 CFR 111.65" as *u8 } 89 if id == CG_RESERVE_SAMPLES { return "21 CFR 111.83" as *u8 } 90 if id == CG_TRAINED_PERSONNEL { return "21 CFR 111.13" as *u8 } 91 if id == CG_SANITARY_PLANT { return "21 CFR 111.15" as *u8 } 92 if id == CG_CALIBRATED_EQUIP { return "21 CFR 111.27" as *u8 } 93 if id == CG_LAB_CONTROLS { return "21 CFR 111.320" as *u8 } 94 if id == CG_COMPLAINTS { return "21 CFR 111.560" as *u8 } 95 if id == CG_RECORDS { return "21 CFR 111.605" as *u8 } 96 return "n/a" as *u8 97} 98 99// Criticality: the CRITICAL set is the warning-letter cluster. 100func cg_criticality(id: i64) -> i64 { 101 if id == CG_SPECIFICATIONS { return CG_CRITICAL } 102 if id == CG_ID_TESTING { return CG_CRITICAL } 103 if id == CG_FINISHED_TESTING { return CG_CRITICAL } 104 if id == CG_MMR { return CG_CRITICAL } 105 if id == CG_BPR { return CG_CRITICAL } 106 if id == CG_QC_UNIT { return CG_CRITICAL } 107 if id == CG_SUPPLIER_QUAL { return CG_MAJOR } 108 if id == CG_RESERVE_SAMPLES { return CG_MAJOR } 109 if id == CG_TRAINED_PERSONNEL { return CG_MAJOR } 110 if id == CG_SANITARY_PLANT { return CG_MAJOR } 111 if id == CG_CALIBRATED_EQUIP { return CG_MAJOR } 112 if id == CG_LAB_CONTROLS { return CG_MAJOR } 113 if id == CG_COMPLAINTS { return CG_MINOR } 114 if id == CG_RECORDS { return CG_MINOR } 115 return 0 116} 117 118// ===== State: which requirements are met ============================== 119// 120// A bitmask, so a facility's whole cGMP posture is one integer. 121 122struct NxCgmpState { 123 met_mask: i64, 124} 125 126func nx_cgmp_new() -> *NxCgmpState { 127 let s: *NxCgmpState = (sys_mmap(16)) as *NxCgmpState 128 s.met_mask = 0 129 return s 130} 131 132func cg_set_met(s: *NxCgmpState, id: i64) -> i64 { 133 if cg_valid(id) != 1 { return 0 } 134 let bit: i64 = 1 << id 135 s.met_mask = s.met_mask | bit 136 return 1 137} 138 139func cg_is_met(s: *NxCgmpState, id: i64) -> i64 { 140 if cg_valid(id) != 1 { return 0 } 141 let bit: i64 = 1 << id 142 let m: i64 = s.met_mask & bit 143 if m != 0 { return 1 } 144 return 0 145} 146 147// Set every requirement met -- an audit-ready facility, for round-tripping. 148func cg_set_all(s: *NxCgmpState) -> i64 { 149 var i: i64 = 0 150 while i < CG_N { 151 cg_set_met(s, i) 152 i = i + 1 153 } 154 return 0 155} 156 157// ===== Gap analysis =================================================== 158 159// The first UNMET CRITICAL requirement (id order), or -1 if all critical met. 160// This is the "fix this before you even schedule the audit" answer. 161func cg_first_critical_gap(s: *NxCgmpState) -> i64 { 162 var i: i64 = 0 163 var gap: i64 = 0 - 1 164 while i < CG_N { 165 if gap < 0 { 166 if cg_criticality(i) == CG_CRITICAL { 167 if cg_is_met(s, i) != 1 { gap = i } 168 } 169 } 170 i = i + 1 171 } 172 return gap 173} 174 175func cg_critical_gaps(s: *NxCgmpState) -> i64 { 176 var i: i64 = 0 177 var n: i64 = 0 178 while i < CG_N { 179 if cg_criticality(i) == CG_CRITICAL { 180 if cg_is_met(s, i) != 1 { n = n + 1 } 181 } 182 i = i + 1 183 } 184 return n 185} 186 187func cg_total_gaps(s: *NxCgmpState) -> i64 { 188 var i: i64 = 0 189 var n: i64 = 0 190 while i < CG_N { 191 if cg_is_met(s, i) != 1 { n = n + 1 } 192 i = i + 1 193 } 194 return n 195} 196 197// A facility is audit-ready only when EVERY critical requirement is met. A 198// facility with critical gaps is not "nearly ready" -- it is not ready. 199func cg_audit_ready(s: *NxCgmpState) -> i64 { 200 if cg_first_critical_gap(s) < 0 { return 1 } 201 return 0 202} 203 204// Weighted readiness, per-mil. CRITICAL requirements carry the most weight, so 205// the score reflects audit risk, not a raw count. 206func cg_total_weight() -> i64 { 207 var i: i64 = 0 208 var w: i64 = 0 209 while i < CG_N { 210 w = w + cg_criticality(i) 211 i = i + 1 212 } 213 return w 214} 215 216func cg_readiness_permil(s: *NxCgmpState) -> i64 { 217 let total: i64 = cg_total_weight() 218 if total <= 0 { return 0 } 219 var i: i64 = 0 220 var got: i64 = 0 221 while i < CG_N { 222 if cg_is_met(s, i) == 1 { got = got + cg_criticality(i) } 223 i = i + 1 224 } 225 return got * 1000 / total 226} 227 228// The two requirements the production-plan's IDENTITY dimension maps to: 229// established specs + 100% component identity testing. Exposed so the plan's 230// coarse "identity_ready" flag can be DERIVED from the real requirements 231// rather than asserted. 232func cg_identity_dimension_met(s: *NxCgmpState) -> i64 { 233 if cg_is_met(s, CG_SPECIFICATIONS) != 1 { return 0 } 234 if cg_is_met(s, CG_ID_TESTING) != 1 { return 0 } 235 return 1 236}