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}