nx_trial_ethics.nx source
↩ module page · 238 lines · 8668 B
1// nx_trial_ethics.nx -- GTM SUITE / ETHICAL TRIAL PARTNER rung. Scores
2// jurisdictions as places to run clinical development on INTEGRITY axes, not
3// only on cost and speed -- because who you develop with is a choice, and the
4// opioid era is what happens when that choice is made badly.
5//
6// WHY THIS FILE EXISTS. Purdue Pharma pleaded guilty to federal felonies in
7// 2007 and again in 2020 for misrepresenting the addiction risk of OxyContin.
8// That was not a regulator being permissive by design -- it was a regulator
9// being CAPTURED and DECEIVED. Which means the defence is structural: pick
10// systems where independent ethics review, mandatory results disclosure and
11// low institutional corruption make that capture harder. This rung makes that
12// comparable instead of rhetorical.
13//
14// THE AXES, AND WHY EACH ONE IS HERE:
15// CPI Transparency International's Corruption Perceptions
16// Index -- published, 0-100, higher is cleaner. The single
17// best available proxy for institutional capture risk.
18// ICH-GCP adherence to the international good-clinical-practice
19// standard: informed consent, monitoring, data integrity.
20// RESULTS DISCLOSURE mandatory posting of results, including NEGATIVE ones.
21// Selective publication is how OxyContin's risk profile
22// stayed obscured; a regime that compels disclosure is
23// structurally harder to game.
24// ETHICS INDEPENDENCE whether review sits with a body independent of the
25// sponsor and the institution.
26// INJURY COMPENSATION whether a harmed participant is compensated without
27// having to litigate.
28// PORTABILITY whether the data is accepted by FDA and EMA. This
29// matters for a reason worth stating plainly: choosing an
30// ethical partner does NOT cost you the US market, because
31// ICH-compliant foreign data is accepted by FDA. You can
32// decline to develop in a system you distrust and still
33// sell there later.
34//
35// ONE HONEST NON-DIFFERENTIATOR. Industry fee funding of regulators is a real
36// conflict -- FDA's human drugs programme is roughly half user-fee funded, and
37// EMA is MORE fee-dependent, not less. Because it is near-universal it does
38// not separate these jurisdictions, so it is documented here rather than
39// scored, to avoid manufacturing a distinction that does not exist.
40//
41// CPI SCORES ARE PUBLISHED AND MOVE ANNUALLY -- te_cpi_needs_refresh() flags
42// that they are a snapshot, not a constant.
43//
44// Grounding (cited; researcher-groundable):
45// transparency_international_cpi_published_scores
46// ich_e6_good_clinical_practice
47// eu_ctr_536_2014_mandatory_results_disclosure
48// nhmrc_national_statement_ethical_conduct_human_research
49// fda_acceptance_of_foreign_clinical_data_21cfr312_120
50//
51// genealogy_id: drug_development + supplement_gtm
52
53import "nx_syscalls.nx"
54
55// ===== Jurisdictions (sealed) =========================================
56
57const TE_DENMARK: i64 = 0
58const TE_SWEDEN: i64 = 1
59const TE_NETHERLANDS: i64 = 2
60const TE_SWITZERLAND: i64 = 3
61const TE_NEW_ZEALAND: i64 = 4
62const TE_AUSTRALIA: i64 = 5
63const TE_CANADA: i64 = 6
64const TE_UK: i64 = 7
65const TE_US: i64 = 8
66const TE_N: i64 = 9
67
68const TE_INVALID: i64 = 0 - 1
69
70func te_name(j: i64) -> *u8 {
71 if j == TE_DENMARK { return "Denmark" as *u8 }
72 if j == TE_SWEDEN { return "Sweden" as *u8 }
73 if j == TE_NETHERLANDS { return "Netherlands" as *u8 }
74 if j == TE_SWITZERLAND { return "Switzerland" as *u8 }
75 if j == TE_NEW_ZEALAND { return "New Zealand" as *u8 }
76 if j == TE_AUSTRALIA { return "Australia" as *u8 }
77 if j == TE_CANADA { return "Canada" as *u8 }
78 if j == TE_UK { return "United Kingdom" as *u8 }
79 if j == TE_US { return "United States" as *u8 }
80 return "UNKNOWN" as *u8
81}
82
83func te_valid(j: i64) -> i64 {
84 if j < 0 { return 0 }
85 if j >= TE_N { return 0 }
86 return 1
87}
88
89// ===== Integrity axes =================================================
90
91// Transparency International CPI, 0-100, higher is cleaner. Published figures.
92func te_cpi(j: i64) -> i64 {
93 if j == TE_DENMARK { return 90 }
94 if j == TE_SWEDEN { return 82 }
95 if j == TE_NETHERLANDS { return 78 }
96 if j == TE_SWITZERLAND { return 81 }
97 if j == TE_NEW_ZEALAND { return 83 }
98 if j == TE_AUSTRALIA { return 77 }
99 if j == TE_CANADA { return 75 }
100 if j == TE_UK { return 71 }
101 if j == TE_US { return 65 }
102 return TE_INVALID
103}
104
105// CPI is a yearly snapshot, not a constant.
106func te_cpi_needs_refresh(j: i64) -> i64 {
107 return 1
108}
109
110func te_ich_gcp(j: i64) -> i64 {
111 if te_valid(j) != 1 { return 0 }
112 return 1
113}
114
115// Mandatory posting of results INCLUDING negative ones.
116func te_mandatory_results_disclosure(j: i64) -> i64 {
117 if j == TE_DENMARK { return 1 }
118 if j == TE_SWEDEN { return 1 }
119 if j == TE_NETHERLANDS { return 1 }
120 if j == TE_SWITZERLAND { return 1 }
121 if j == TE_UK { return 1 }
122 if j == TE_US { return 1 }
123 if j == TE_AUSTRALIA { return 0 }
124 if j == TE_NEW_ZEALAND { return 0 }
125 if j == TE_CANADA { return 0 }
126 return 0
127}
128
129// Ethics review by a body independent of sponsor and institution.
130func te_independent_ethics(j: i64) -> i64 {
131 if te_valid(j) != 1 { return 0 }
132 return 1
133}
134
135// Participant injury compensation without having to litigate.
136func te_no_fault_injury_compensation(j: i64) -> i64 {
137 if j == TE_NEW_ZEALAND { return 1 } // ACC covers trial injury
138 if j == TE_DENMARK { return 1 }
139 if j == TE_SWEDEN { return 1 }
140 if j == TE_SWITZERLAND { return 1 }
141 return 0
142}
143
144// Data accepted by BOTH FDA and EMA.
145func te_data_portable(j: i64) -> i64 {
146 if te_valid(j) != 1 { return 0 }
147 return 1
148}
149
150// Documented, deliberately NOT scored: near-universal, so it separates nobody.
151func te_regulator_fee_funded(j: i64) -> i64 {
152 if te_valid(j) != 1 { return 0 }
153 return 1
154}
155
156// ===== Composite integrity score ======================================
157//
158// CPI carries the most weight because institutional capture is the failure
159// mode that produced the opioid crisis; the binary protections add on top.
160// Max = 100 + 4*10 = 140.
161
162const TE_BINARY_WEIGHT: i64 = 10
163
164func te_integrity_score(j: i64) -> i64 {
165 if te_valid(j) != 1 { return TE_INVALID }
166 let cpi: i64 = te_cpi(j)
167 if cpi == TE_INVALID { return TE_INVALID }
168 var s: i64 = cpi
169 let a: i64 = te_ich_gcp(j)
170 let b: i64 = te_mandatory_results_disclosure(j)
171 let c: i64 = te_independent_ethics(j)
172 let d: i64 = te_no_fault_injury_compensation(j)
173 let bins: i64 = a + b + c + d
174 s = s + bins * TE_BINARY_WEIGHT
175 return s
176}
177
178// Highest integrity score. Computed across all, not asserted.
179func te_most_ethical() -> i64 {
180 var j: i64 = 0
181 var best: i64 = TE_INVALID
182 var bests: i64 = TE_INVALID
183 while j < TE_N {
184 let s: i64 = te_integrity_score(j)
185 if s != TE_INVALID {
186 if best == TE_INVALID { best = j; bests = s }
187 if s > bests { best = j; bests = s }
188 }
189 j = j + 1
190 }
191 return best
192}
193
194// How many jurisdictions here out-score a given one on integrity.
195func te_rank_of(j: i64) -> i64 {
196 let mine: i64 = te_integrity_score(j)
197 if mine == TE_INVALID { return TE_INVALID }
198 var k: i64 = 0
199 var above: i64 = 0
200 while k < TE_N {
201 let s: i64 = te_integrity_score(k)
202 if s != TE_INVALID {
203 if s > mine { above = above + 1 }
204 }
205 k = k + 1
206 }
207 return above + 1
208}
209
210// ===== The reassurance that matters ===================================
211//
212// Declining to develop in a jurisdiction does NOT forfeit its market, because
213// ICH-compliant foreign data is accepted (21 CFR 312.120). Encoded as a
214// function so the planner treats it as a fact, not a hope.
215func te_ethical_choice_forfeits_us_market(j: i64) -> i64 {
216 let p: i64 = te_data_portable(j)
217 if p == 1 { return 0 }
218 return 1
219}
220
221// Jurisdictions that beat a reference one on integrity AND keep data portable.
222func te_count_better_and_portable(reference: i64) -> i64 {
223 let mine: i64 = te_integrity_score(reference)
224 if mine == TE_INVALID { return TE_INVALID }
225 var k: i64 = 0
226 var n: i64 = 0
227 while k < TE_N {
228 let s: i64 = te_integrity_score(k)
229 if s != TE_INVALID {
230 if s > mine {
231 let p: i64 = te_data_portable(k)
232 n = n + p
233 }
234 }
235 k = k + 1
236 }
237 return n
238}