code wiki / (root) / nx_supp_claims.nx

nx_supp_claims.nx source

↩ module page · 221 lines · 9112 B

1// nx_supp_claims.nx -- SUPPLEMENT GTM SUITE / LABEL CLAIMS rung. Classifies a 2// marketing sentence as a lawful structure/function claim or an unlawful 3// disease claim, because that line is where supplement companies actually get 4// warning letters -- more often than for the formula itself. 5// 6// THE LAW IN ONE SENTENCE. A supplement may say what an ingredient does to 7// the normal structure or function of the body. The moment it says the 8// product diagnoses, mitigates, treats, cures or prevents a DISEASE, it is 9// making a drug claim, and an unapproved drug claim makes the product an 10// unapproved drug -- 21 CFR 101.93(g) sets out the criteria this implements. 11// 12// THE PAIRS THAT MATTER, and they are closer than they look: 13// LAWFUL "helps maintain healthy cholesterol levels already in normal range" 14// UNLAWFUL "lowers cholesterol" (implies treating hypercholesterolemia) 15// LAWFUL "supports healthy sexual function" 16// UNLAWFUL "treats female sexual arousal disorder" 17// UNLAWFUL "works alongside your antidepressant to fix SSRI side effects" 18// -- this one is doubly bad: it is a disease claim AND an 19// AUGMENTS-A-THERAPY claim under 101.93(g)(2)(viii). 20// 21// THAT LAST CASE IS WORTH SAYING PLAINLY: the framing "famously used to treat 22// antidepressant-induced sexual dysfunction", which is how ginkgo is usually 23// described in this category, CANNOT go on a label. The underlying research 24// may be perfectly real -- the sentence is still a drug claim. 25// 26// NATURAL STATES ARE NOT DISEASES. FDA is explicit that menopause, pregnancy, 27// aging and adolescence are normal life stages, so "for the relief of hot 28// flashes associated with menopause" is a lawful structure/function claim 29// while "for the treatment of osteoporosis" is not. A classifier that 30// flagged "menopause" as a disease term would be wrong in a way that costs 31// real, lawful marketing -- so the lexicon carves them out explicitly. 32// 33// FAIL-CLOSED, AND DELIBERATELY SO. A sentence with no disease trigger but 34// also no recognisable structure/function frame returns NEEDS_REVIEW, not OK. 35// This organ can retire the easy calls; it cannot replace counsel, and 36// pretending otherwise would be the expensive kind of wrong. 37// 38// Grounding (cited; researcher-groundable): 39// fda_21cfr101_93_structure_function_vs_disease_claims 40// fda_21cfr101_93_g_2_disease_claim_criteria 41// dshea_disclaimer_and_30_day_notification_101_93_c 42// fda_guidance_natural_state_menopause_pregnancy_aging 43// 44// genealogy_id: supplement_gtm + nishi_food_science_suite 45 46import "nx_syscalls.nx" 47 48// ===== Verdicts (sealed) ============================================== 49 50const CL_NEEDS_REVIEW: i64 = 0 // no trigger, no clear S/F frame 51const CL_STRUCTURE_FUNC: i64 = 1 // lawful, with disclaimer + notification 52const CL_DISEASE_CLAIM: i64 = 2 // unlawful without drug approval 53const CL_DRUG_REFERENCE: i64 = 3 // substitutes for / augments a therapy 54const CL_EMPTY: i64 = 4 55 56// A lawful structure/function claim carries BOTH obligations. 57const CL_DISCLAIMER_REQUIRED: i64 = 1 58const CL_NOTIFY_FDA_DAYS: i64 = 30 59 60// ===== Case-insensitive substring search ============================== 61 62func cl_lower(c: i64) -> i64 { 63 if c >= 65 { if c <= 90 { return c + 32 } } 64 return c 65} 66 67func cl_len(s: *u8) -> i64 { 68 var i: i64 = 0 69 while s[i] != (0 as u8) { i = i + 1 } 70 return i 71} 72 73// Index of needle in hay, case-insensitive, or -1. No break in this language, 74// so the scan latches the first hit and runs to completion. 75func cl_find(hay: *u8, needle: *u8) -> i64 { 76 let hn: i64 = cl_len(hay) 77 let nn: i64 = cl_len(needle) 78 if nn <= 0 { return 0 - 1 } 79 if nn > hn { return 0 - 1 } 80 var i: i64 = 0 81 var found: i64 = 0 - 1 82 let last: i64 = hn - nn 83 while i <= last { 84 if found < 0 { 85 var j: i64 = 0 86 var ok: i64 = 1 87 while j < nn { 88 let a: i64 = cl_lower(hay[i + j] as i64) 89 let b: i64 = cl_lower(needle[j] as i64) 90 if a != b { ok = 0 } 91 j = j + 1 92 } 93 if ok == 1 { found = i } 94 } 95 i = i + 1 96 } 97 return found 98} 99 100func cl_has(hay: *u8, needle: *u8) -> i64 { 101 let p: i64 = cl_find(hay, needle) 102 if p >= 0 { return 1 } 103 return 0 104} 105 106// ===== Lexicons ======================================================= 107// 108// Split into small predicates rather than one giant scan so each category 109// can be tested, cited and extended on its own. 110 111// Verbs that assert a therapeutic effect on a disease. 112func cl_has_disease_verb(s: *u8) -> i64 { 113 if cl_has(s, "treat" as *u8) == 1 { return 1 } 114 if cl_has(s, "cure" as *u8) == 1 { return 1 } 115 if cl_has(s, "prevent" as *u8) == 1 { return 1 } 116 if cl_has(s, "diagnos" as *u8) == 1 { return 1 } 117 if cl_has(s, "mitigat" as *u8) == 1 { return 1 } 118 if cl_has(s, "remedy" as *u8) == 1 { return 1 } 119 if cl_has(s, "heals" as *u8) == 1 { return 1 } 120 if cl_has(s, "reverses" as *u8) == 1 { return 1 } 121 return 0 122} 123 124// Nouns naming a disease or disease class. "dysfunction" and "disorder" are 125// the two that catch this product category. 126func cl_has_disease_noun(s: *u8) -> i64 { 127 if cl_has(s, "disease" as *u8) == 1 { return 1 } 128 if cl_has(s, "disorder" as *u8) == 1 { return 1 } 129 if cl_has(s, "dysfunction" as *u8) == 1 { return 1 } 130 if cl_has(s, "syndrome" as *u8) == 1 { return 1 } 131 if cl_has(s, "impotence" as *u8) == 1 { return 1 } 132 if cl_has(s, "infertility" as *u8) == 1 { return 1 } 133 if cl_has(s, "depression" as *u8) == 1 { return 1 } 134 if cl_has(s, "hypogonadism" as *u8) == 1 { return 1 } 135 if cl_has(s, "osteoporosis" as *u8) == 1 { return 1 } 136 return 0 137} 138 139// Naming a drug, or positioning against one. 101.93(g)(2)(vii) and (viii). 140func cl_has_drug_reference(s: *u8) -> i64 { 141 if cl_has(s, "viagra" as *u8) == 1 { return 1 } 142 if cl_has(s, "addyi" as *u8) == 1 { return 1 } 143 if cl_has(s, "vyleesi" as *u8) == 1 { return 1 } 144 if cl_has(s, "cialis" as *u8) == 1 { return 1 } 145 if cl_has(s, "antidepressant" as *u8) == 1 { return 1 } 146 if cl_has(s, "ssri" as *u8) == 1 { return 1 } 147 if cl_has(s, "prescription" as *u8) == 1 { return 1 } 148 if cl_has(s, "alternative to" as *u8) == 1 { return 1 } 149 if cl_has(s, "instead of" as *u8) == 1 { return 1 } 150 if cl_has(s, "replaces your" as *u8) == 1 { return 1 } 151 if cl_has(s, "works alongside your" as *u8) == 1 { return 1 } 152 return 0 153} 154 155// Recognised lawful framings. 156func cl_has_sf_frame(s: *u8) -> i64 { 157 if cl_has(s, "supports" as *u8) == 1 { return 1 } 158 if cl_has(s, "helps maintain" as *u8) == 1 { return 1 } 159 if cl_has(s, "promotes" as *u8) == 1 { return 1 } 160 if cl_has(s, "maintains healthy" as *u8) == 1 { return 1 } 161 if cl_has(s, "helps support" as *u8) == 1 { return 1 } 162 if cl_has(s, "contributes to" as *u8) == 1 { return 1 } 163 return 0 164} 165 166// Normal life stages FDA does NOT treat as diseases. Present so the disease 167// lexicon cannot swallow lawful menopause and aging claims. 168func cl_has_natural_state(s: *u8) -> i64 { 169 if cl_has(s, "menopause" as *u8) == 1 { return 1 } 170 if cl_has(s, "pregnan" as *u8) == 1 { return 1 } 171 if cl_has(s, "aging" as *u8) == 1 { return 1 } 172 if cl_has(s, "adolescen" as *u8) == 1 { return 1 } 173 return 0 174} 175 176// ===== The classifier ================================================= 177// 178// Order matters: a drug reference is checked FIRST because "an alternative to 179// Viagra" carries no disease noun at all yet is squarely a drug claim, and 180// checking disease terms first would let it through as merely unreviewed. 181 182func cl_classify(s: *u8) -> i64 { 183 let n: i64 = cl_len(s) 184 if n <= 0 { return CL_EMPTY } 185 if cl_has_drug_reference(s) == 1 { return CL_DRUG_REFERENCE } 186 if cl_has_disease_noun(s) == 1 { return CL_DISEASE_CLAIM } 187 let nat: i64 = cl_has_natural_state(s) 188 // A therapeutic verb applied to a NATURAL STATE is genuinely ambiguous -- 189 // "relieves hot flashes of menopause" is lawful, "treats menopause" is 190 // not, and the difference is context a lexicon cannot resolve. Send it to 191 // review rather than guess in either direction. 192 if cl_has_disease_verb(s) == 1 { 193 if nat == 1 { return CL_NEEDS_REVIEW } 194 return CL_DISEASE_CLAIM 195 } 196 if nat == 1 { 197 if cl_has(s, "relief" as *u8) == 1 { return CL_STRUCTURE_FUNC } 198 } 199 if cl_has_sf_frame(s) == 1 { return CL_STRUCTURE_FUNC } 200 return CL_NEEDS_REVIEW 201} 202 203func cl_is_lawful(s: *u8) -> i64 { 204 let v: i64 = cl_classify(s) 205 if v == CL_STRUCTURE_FUNC { return 1 } 206 return 0 207} 208 209// A lawful S/F claim triggers the DSHEA disclaimer and a 30-day notification 210// to FDA under 101.93(c). Both, not either. 211func cl_requires_disclaimer(s: *u8) -> i64 { 212 let v: i64 = cl_classify(s) 213 if v == CL_STRUCTURE_FUNC { return CL_DISCLAIMER_REQUIRED } 214 return 0 215} 216 217func cl_notification_days(s: *u8) -> i64 { 218 let v: i64 = cl_classify(s) 219 if v == CL_STRUCTURE_FUNC { return CL_NOTIFY_FDA_DAYS } 220 return 0 221}