code wiki / (root) / nx_supply_risk.nx

nx_supply_risk.nx source

↩ module page · 269 lines · 10351 B

1// nx_supply_risk.nx -- GTM SUITE / MANUFACTURING SOURCING + APPROVAL RISK rung. 2// Where to make the material, what importing your own rigor actually costs, 3// and what any of it does to the odds of approval. 4// 5// THE CENTRAL QUESTION THIS ANSWERS: can you buy a cheap manufacturing base 6// and supply the discipline yourself? Largely YES -- GMP is INSPECTION-based, 7// not nationality-based. A facility in Hyderabad holding an EU-GMP 8// certificate and a clean FDA inspection record is legally equivalent to one 9// in Basel, and roughly half of US generic supply already comes from India. 10// Quality Agreements, vendor qualification, person-in-plant and independent 11// lot release are precisely the mechanism for importing rigor, and large 12// sponsors do it every day. 13// 14// BUT THE RIGOR IS NOT FREE, AND THAT IS THE WHOLE FINDING. Model the true 15// cost -- sticker + audit burden + the expected cost of an inspection-driven 16// delay -- and the cheap options CONVERGE. On a $10M API spend the effective 17// costs of India, Poland and China land within a few percent of one another, 18// because the sticker advantage of the cheapest is eaten by its risk premium. 19// Once that is visible, the right basis for choosing is quality of access and 20// regulatory adjacency, NOT the quoted price. Choosing on sticker alone is 21// choosing the risk without pricing it. 22// 23// AN IRONY WORTH NAMING. The dominant failure mode at low-cost sites is DATA 24// INTEGRITY -- falsified or selectively reported records, the Ranbaxy 2013 25// felony plea being the canonical case. That is the SAME failure mode as the 26// opioid scandal, in a different jurisdiction and a different direction. 27// Fleeing one does not escape the class; only auditing does. 28// 29// ON APPROVAL RISK. FDA does not reject drugs for being foreign -- most new 30// approvals involve foreign data and foreign manufacture. What it does reject 31// is (a) a dataset drawn from a single non-representative population, and 32// (b) a facility that fails inspection. Both are manageable and both are 33// under sponsor control, which is why they are modelled here as inputs 34// rather than as fate. 35// 36// Costs in THOUSANDS of USD; probabilities in per-mil. 37// 38// Grounding (cited; researcher-groundable): 39// fda_foreign_facility_inspection_and_oai_classification 40// ich_q7_gmp_active_pharmaceutical_ingredients 41// fda_21cfr312_120_acceptance_of_foreign_clinical_data 42// fda_multiregional_clinical_trial_ich_e17 43// ranbaxy_2013_data_integrity_felony_plea 44// 45// genealogy_id: drug_development + supplement_gtm 46 47import "nx_syscalls.nx" 48const SR_MAGIC_1100: i64 = 1100 49 50// ===== Manufacturing bases (sealed) =================================== 51 52const SR_SWITZERLAND: i64 = 0 53const SR_US: i64 = 1 54const SR_IRELAND: i64 = 2 55const SR_KOREA: i64 = 3 56const SR_POLAND: i64 = 4 57const SR_INDIA: i64 = 5 58const SR_CHINA: i64 = 6 59const SR_N: i64 = 7 60 61const SR_INVALID: i64 = 0 - 1 62 63func sr_name(s: i64) -> *u8 { 64 if s == SR_SWITZERLAND { return "Switzerland" as *u8 } 65 if s == SR_US { return "United States" as *u8 } 66 if s == SR_IRELAND { return "Ireland" as *u8 } 67 if s == SR_KOREA { return "South Korea" as *u8 } 68 if s == SR_POLAND { return "Poland / EU-East" as *u8 } 69 if s == SR_INDIA { return "India" as *u8 } 70 if s == SR_CHINA { return "China" as *u8 } 71 return "UNKNOWN" as *u8 72} 73 74func sr_valid(s: i64) -> i64 { 75 if s < 0 { return 0 } 76 if s >= SR_N { return 0 } 77 return 1 78} 79 80// ===== Sticker cost =================================================== 81 82// Quoted manufacturing cost, per-mil of the US baseline. 83func sr_cost_permil(s: i64) -> i64 { 84 if s == SR_SWITZERLAND { return SR_MAGIC_1100 } 85 if s == SR_US { return 1000 } 86 if s == SR_IRELAND { return 900 } 87 if s == SR_KOREA { return 700 } 88 if s == SR_POLAND { return 600 } 89 if s == SR_INDIA { return 420 } 90 if s == SR_CHINA { return 350 } 91 return SR_INVALID 92} 93 94// ===== The cost of importing rigor ==================================== 95// 96// Annual quality-oversight burden in $k: vendor qualification, Quality 97// Agreement, person-in-plant, unannounced audits, and independent lot 98// release testing. It rises where oversight distance and data-integrity risk 99// rise -- which is exactly where the sticker is lowest. 100 101func sr_audit_burden_k(s: i64) -> i64 { 102 if s == SR_SWITZERLAND { return 50 } 103 if s == SR_US { return 50 } 104 if s == SR_IRELAND { return 60 } 105 if s == SR_KOREA { return 120 } 106 if s == SR_POLAND { return 100 } 107 if s == SR_INDIA { return 250 } 108 if s == SR_CHINA { return 320 } 109 return SR_INVALID 110} 111 112// Probability of an inspection-driven finding that delays the programme, 113// per-mil. Indicative, from published FDA OAI classification patterns. 114func sr_inspection_fail_permil(s: i64) -> i64 { 115 if s == SR_SWITZERLAND { return 30 } 116 if s == SR_US { return 60 } 117 if s == SR_IRELAND { return 40 } 118 if s == SR_KOREA { return 80 } 119 if s == SR_POLAND { return 90 } 120 if s == SR_INDIA { return 180 } 121 if s == SR_CHINA { return 220 } 122 return SR_INVALID 123} 124 125// Cost of an inspection-driven delay: roughly a year of programme burn. 126const SR_DELAY_COST_K: i64 = 18000 127 128func sr_expected_delay_cost_k(s: i64) -> i64 { 129 let p: i64 = sr_inspection_fail_permil(s) 130 if p == SR_INVALID { return SR_INVALID } 131 return p * SR_DELAY_COST_K / 1000 132} 133 134// EU-GMP certification available locally -- the practical passport, since an 135// EU-GMP certificate plus a clean FDA record travels. 136func sr_eu_gmp_available(s: i64) -> i64 { 137 if sr_valid(s) != 1 { return 0 } 138 return 1 139} 140 141// ===== Effective cost ================================================= 142// 143// sticker + audit burden + expected delay. This is the number to compare; 144// the quote alone is not. 145 146func sr_sticker_cost_k(s: i64, spend_k: i64) -> i64 { 147 let m: i64 = sr_cost_permil(s) 148 if m == SR_INVALID { return SR_INVALID } 149 if spend_k < 0 { return SR_INVALID } 150 return spend_k * m / 1000 151} 152 153func sr_effective_cost_k(s: i64, spend_k: i64) -> i64 { 154 let base: i64 = sr_sticker_cost_k(s, spend_k) 155 if base == SR_INVALID { return SR_INVALID } 156 let aud: i64 = sr_audit_burden_k(s) 157 let del: i64 = sr_expected_delay_cost_k(s) 158 if aud == SR_INVALID { return SR_INVALID } 159 if del == SR_INVALID { return SR_INVALID } 160 return base + aud + del 161} 162 163// How much of the sticker saving survives the risk premium, per-mil of the 164// sticker saving. Low means the discount was mostly illusory. 165func sr_saving_retained_permil(s: i64, spend_k: i64) -> i64 { 166 let base_us: i64 = sr_sticker_cost_k(SR_US, spend_k) 167 let eff_us: i64 = sr_effective_cost_k(SR_US, spend_k) 168 let base_s: i64 = sr_sticker_cost_k(s, spend_k) 169 let eff_s: i64 = sr_effective_cost_k(s, spend_k) 170 if base_s == SR_INVALID { return SR_INVALID } 171 let sticker_saving: i64 = base_us - base_s 172 if sticker_saving <= 0 { return 0 } 173 let real_saving: i64 = eff_us - eff_s 174 if real_saving <= 0 { return 0 } 175 return real_saving * 1000 / sticker_saving 176} 177 178// Cheapest on EFFECTIVE cost, computed across all bases. 179func sr_best_effective(spend_k: i64) -> i64 { 180 var s: i64 = 0 181 var best: i64 = SR_INVALID 182 var bestc: i64 = 0 183 while s < SR_N { 184 let c: i64 = sr_effective_cost_k(s, spend_k) 185 if c != SR_INVALID { 186 if best == SR_INVALID { best = s; bestc = c } 187 if c < bestc { best = s; bestc = c } 188 } 189 s = s + 1 190 } 191 return best 192} 193 194// Cheapest on STICKER -- kept so the two can be compared, because they are 195// frequently different bases and that difference is the point. 196func sr_best_sticker(spend_k: i64) -> i64 { 197 var s: i64 = 0 198 var best: i64 = SR_INVALID 199 var bestc: i64 = 0 200 while s < SR_N { 201 let c: i64 = sr_sticker_cost_k(s, spend_k) 202 if c != SR_INVALID { 203 if best == SR_INVALID { best = s; bestc = c } 204 if c < bestc { best = s; bestc = c } 205 } 206 s = s + 1 207 } 208 return best 209} 210 211// Do the low-cost options land within tol per-mil of each other on effective 212// cost? If so, choosing on sticker is choosing risk without pricing it. 213func sr_low_cost_converged(spend_k: i64, tol_permil: i64) -> i64 { 214 let a: i64 = sr_effective_cost_k(SR_INDIA, spend_k) 215 let b: i64 = sr_effective_cost_k(SR_POLAND, spend_k) 216 let c: i64 = sr_effective_cost_k(SR_CHINA, spend_k) 217 if a == SR_INVALID { return 0 } 218 var lo: i64 = a 219 var hi: i64 = a 220 if b < lo { lo = b } 221 if b > hi { hi = b } 222 if c < lo { lo = c } 223 if c > hi { hi = c } 224 if lo <= 0 { return 0 } 225 let spread: i64 = (hi - lo) * 1000 / lo 226 if spread <= tol_permil { return 1 } 227 return 0 228} 229 230// ===== Approval risk ================================================== 231// 232// Modelled as sponsor-controlled inputs, because they are. 233 234const SR_APPROVAL_OK: i64 = 1 235const SR_RISK_SINGLE_POPULATION: i64 = 2 236const SR_RISK_FACILITY_INSPECTION: i64 = 3 237 238// FDA accepts foreign clinical data (21 CFR 312.120). What it challenges is a 239// dataset from ONE non-representative population -- the concrete precedent 240// being the 2022 refusal of an approval sought on China-only trial data. 241// Multiregional design under ICH E17 removes this risk. 242func sr_data_applicability_risk(multiregional: i64, n_regions: i64) -> i64 { 243 if multiregional == 1 { 244 if n_regions >= 2 { return 0 } 245 } 246 return 1 247} 248 249// The two things that actually stop a foreign-developed application. 250func sr_approval_blocker(multiregional: i64, n_regions: i64, site: i64) -> i64 { 251 let d: i64 = sr_data_applicability_risk(multiregional, n_regions) 252 if d == 1 { return SR_RISK_SINGLE_POPULATION } 253 let p: i64 = sr_inspection_fail_permil(site) 254 if p == SR_INVALID { return SR_RISK_FACILITY_INSPECTION } 255 return SR_APPROVAL_OK 256} 257 258// Being foreign is NOT itself a barrier. Encoded as a function so a planner 259// treats it as a modelled fact rather than an assumption either way. 260func sr_foreign_origin_is_a_barrier() -> i64 { 261 return 0 262} 263 264// The regulator-capture failure that produced the opioid crisis ran toward 265// APPROVING a dangerous product under industry pressure, not toward blocking 266// a good one. Recorded because it bears directly on which risk to plan for. 267func sr_capture_bias_favours_approval() -> i64 { 268 return 1 269}