code wiki / (root) / nx_trial_ethics.nx

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}