code wiki / (root) / nx_chem_adulterant_db_test.nx

nx_chem_adulterant_db_test.nx source

↩ module page · 468 lines · 23850 B

1// nx_chem_adulterant_db_test.nx -- C4.0 KAT + END-TO-END lab demo. 2// 3// The KAT validates that the seed DB parses correctly, m/z values 4// match published reference, and lookup-by-m/z returns expected 5// matches. The demo at the end prints a realistic lab-report output 6// for a synthetic 4-peak LC-MS observation. 7// 8// expect_exit: 0 9// license_tier: ORIGINAL 10 11import "nx_chem.nx" 12import "nx_chem_molecule.nx" 13import "nx_chem_smiles.nx" 14import "nx_chem_periodic.nx" 15import "nx_chem_valence.nx" 16import "nx_chem_mass.nx" 17import "nx_chem_isotope_pattern.nx" 18import "nx_chem_adulterant_db.nx" 19import "nx_chem_peak_list.nx" 20 21// ================================================================= 22// A -- seed DB must populate 24 entries 23// ================================================================= 24func a_seed_count() -> nx_int { 25 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 26 if db.n != 33 { return 11 } 27 return 0 28} 29 30// ================================================================= 31// B -- sibutramine entry (id=4) must have halogen signature 1 (Cl) 32// and be flagged BANNED 33// ================================================================= 34func b_sibutramine_signature() -> nx_int { 35 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 36 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 37 if e.id != 4 { return 21 } 38 if e.halogen_sig != 1 { return 22 } 39 if e.regulatory != NX_REG_BANNED { return 23 } 40 return 0 41} 42 43// ================================================================= 44// C -- caffeine entry (id=5) must have NO halogen signature and be 45// flagged APPROVED (baseline) 46// ================================================================= 47func c_caffeine_signature() -> nx_int { 48 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 49 let e: *AdulterantEntry = ((db.entries as nx_int) + (5 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 50 if e.id != 5 { return 31 } 51 if e.halogen_sig != 0 { return 32 } 52 if e.regulatory != NX_REG_APPROVED { return 33 } 53 return 0 54} 55 56// ================================================================= 57// D -- lookup observed peak at sibutramine [M+H]+ within 5 ppm 58// should return exactly 1 match = id 4 (sibutramine). 59// Sibutramine C17H26ClN [M+H]+ = 280.18 m/z; compute from our DB. 60// ================================================================= 61func d_lookup_sibutramine() -> nx_int { 62 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 63 // Get sibutramine's own [M+H]+ from DB and query at that exact m/z 64 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 65 let target: nx_int = e.mh_plus_q4 66 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 67 let n: nx_int = nx_chem_adulterant_db_lookup_mh_plus(db, target, 5, out, 4) 68 if n != 1 { return 41 } 69 let r0: *MatchResult = ((out as nx_int) + (0 * NX_MATCH_RESULT_BYTES)) as *MatchResult 70 if r0.entry_id != 4 { return 42 } 71 return 0 72} 73 74// ================================================================= 75// E -- lookup at a wildly off-mass peak should return 0 matches 76// ================================================================= 77func e_lookup_no_match() -> nx_int { 78 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 79 let target: nx_int = 9999999 // 999.9999 Da -- nothing in DB matches 80 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 81 let n: nx_int = nx_chem_adulterant_db_lookup_mh_plus(db, target, 5, out, 4) 82 if n != 0 { return 51 } 83 return 0 84} 85 86// ================================================================= 87// F -- 5 ppm tolerance is non-zero: a 3 ppm offset peak SHOULD still match 88// ================================================================= 89func f_lookup_3ppm_offset() -> nx_int { 90 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 91 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 92 // Add 3 ppm offset: target = e.mh_plus_q4 * 1000003 / 1000000 93 let target: nx_int = e.mh_plus_q4 + ((e.mh_plus_q4 * 3) / 1000000) 94 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 95 let n: nx_int = nx_chem_adulterant_db_lookup_mh_plus(db, target, 5, out, 4) 96 if n != 1 { return 61 } 97 return 0 98} 99 100// ================================================================= 101// G -- at 5 ppm tolerance, a 10 ppm offset should NOT match 102// ================================================================= 103func g_lookup_10ppm_offset() -> nx_int { 104 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 105 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 106 let target: nx_int = e.mh_plus_q4 + ((e.mh_plus_q4 * 10) / 1000000) 107 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 108 let n: nx_int = nx_chem_adulterant_db_lookup_mh_plus(db, target, 5, out, 4) 109 if n != 0 { return 71 } 110 return 0 111} 112 113// ================================================================= 114// I -- C7.0 RT filter: when ref_rt unset (0), lookup_with_rt is 115// mass-only and behaves identically to lookup_mh_plus 116// ================================================================= 117func i_rt_lookup_no_ref_rt() -> nx_int { 118 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 119 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 120 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 121 let n: nx_int = nx_chem_adulterant_db_lookup_with_rt(db, e.mh_plus_q4, 1000000, 5, out, 4) 122 if n != 1 { return 111 } 123 let r0: *MatchResult = ((out as nx_int) + (0 * NX_MATCH_RESULT_BYTES)) as *MatchResult 124 if r0.entry_id != 4 { return 112 } 125 return 0 126} 127 128// ================================================================= 129// J -- C7.0 set ref_rt, then off-rt query within mass tolerance 130// should be REJECTED by the RT filter 131// ================================================================= 132func j_rt_off_rejected() -> nx_int { 133 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 134 // Set ref_rt for sibutramine to 740 sec (740000 ms) ± 30 sec 135 let _s: nx_int = nx_chem_adulterant_db_set_rt(db, 4, 740000, 30000) 136 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 137 // Query at sibutramine mass + RT 1000s (260s off from ref 740s -- way outside tol) 138 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 139 let n: nx_int = nx_chem_adulterant_db_lookup_with_rt(db, e.mh_plus_q4, 1000000, 5, out, 4) 140 if n != 0 { return 121 } 141 return 0 142} 143 144// ================================================================= 145// K -- C7.0 set ref_rt, then on-rt query within mass + RT tolerance 146// should MATCH 147// ================================================================= 148func k_rt_on_matches() -> nx_int { 149 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 150 let _s: nx_int = nx_chem_adulterant_db_set_rt(db, 4, 740000, 30000) 151 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 152 // Query at ref RT 750s = 10s offset (within ±30s tol) 153 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 154 let n: nx_int = nx_chem_adulterant_db_lookup_with_rt(db, e.mh_plus_q4, 750000, 5, out, 4) 155 if n != 1 { return 131 } 156 return 0 157} 158 159// ================================================================= 160// L -- C7.0 RT filter is bypassed if observed RT is 0 (caller didn't 161// provide RT info), even when ref_rt is set 162// ================================================================= 163func l_rt_zero_observed_bypasses() -> nx_int { 164 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 165 let _s: nx_int = nx_chem_adulterant_db_set_rt(db, 4, 740000, 30000) 166 let e: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 167 let out: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 168 let n: nx_int = nx_chem_adulterant_db_lookup_with_rt(db, e.mh_plus_q4, 0, 5, out, 4) 169 if n != 1 { return 141 } 170 return 0 171} 172 173// ================================================================= 174// H -- 8 entries' m/z values should all be distinct 175// (sanity check the seed data doesn't have accidental collisions) 176// ================================================================= 177func h_distinct_mz() -> nx_int { 178 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 179 var i: nx_int = 0 180 while i < db.n { 181 let ei: *AdulterantEntry = ((db.entries as nx_int) + (i * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 182 var j: nx_int = i + 1 183 while j < db.n { 184 let ej: *AdulterantEntry = ((db.entries as nx_int) + (j * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 185 if ei.mh_plus_q4 == ej.mh_plus_q4 { 186 // Allow same m/z only if the SMILES happen to be the same 187 // formula by coincidence; flag for review. 188 return 81 189 } 190 j = j + 1 191 } 192 i = i + 1 193 } 194 return 0 195} 196 197// ================================================================= 198// O -- C4.3 load compounds from disk file (DB extensibility) 199// ================================================================= 200func o_load_compounds() -> nx_int { 201 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 202 let initial_count: nx_int = db.n 203 // Build CSV-like text with two compounds 204 // "100|test1|CCO|1|test approved\n101|test2|CC(N)C|3|test banned\n" 205 let src: *u8 = sys_mmap(256) 206 src[0] = 0x31; src[1] = 0x30; src[2] = 0x30; src[3] = 0x7C // "100|" 207 src[4] = 0x74; src[5] = 0x65; src[6] = 0x73; src[7] = 0x74; src[8] = 0x31; src[9] = 0x7C // "test1|" 208 src[10] = 0x43; src[11] = 0x43; src[12] = 0x4F; src[13] = 0x7C // "CCO|" 209 src[14] = 0x31; src[15] = 0x7C // "1|" 210 src[16] = 0x74; src[17] = 0x65; src[18] = 0x73; src[19] = 0x74; src[20] = 0x20; src[21] = 0x61; src[22] = 0x70; src[23] = 0x70; src[24] = 0x72 // "test appr" 211 src[25] = 0x0A 212 src[26] = 0x31; src[27] = 0x30; src[28] = 0x31; src[29] = 0x7C // "101|" 213 src[30] = 0x74; src[31] = 0x65; src[32] = 0x73; src[33] = 0x74; src[34] = 0x32; src[35] = 0x7C // "test2|" 214 src[36] = 0x43; src[37] = 0x43; src[38] = 0x28; src[39] = 0x4E; src[40] = 0x29; src[41] = 0x43; src[42] = 0x7C // "CC(N)C|" 215 src[43] = 0x33; src[44] = 0x7C // "3|" 216 src[45] = 0x74; src[46] = 0x65; src[47] = 0x73; src[48] = 0x74; src[49] = 0x20; src[50] = 0x62; src[51] = 0x61; src[52] = 0x6E // "test ban" 217 src[53] = 0x0A 218 let n_src: nx_int = 54 219 let path: *u8 = sys_mmap(64) 220 path[0] = 0x2F; path[1] = 0x74; path[2] = 0x6D; path[3] = 0x70 221 path[4] = 0x2F; path[5] = 0x6E; path[6] = 0x78; path[7] = 0x5F 222 path[8] = 0x6C; path[9] = 0x6F; path[10] = 0x61; path[11] = 0x64 223 path[12] = 0x5F; path[13] = 0x6B; path[14] = 0x61; path[15] = 0x74 224 path[16] = 0x2E; path[17] = 0x74; path[18] = 0x73; path[19] = 0x76 225 path[20] = 0 226 let nw: nx_int = nx_chem_write_file(path, src, n_src) 227 if nw != n_src { return 171 } 228 let n_loaded: nx_int = nx_chem_load_compounds_from_file(db, path) 229 if n_loaded != 2 { return 172 } 230 if db.n != initial_count + 2 { return 173 } 231 // Lookup test1 by id 100 232 let e1: *AdulterantEntry = nx_chem_adulterant_entry_by_id(db, 100) 233 if (e1 as nx_int) == 0 { return 174 } 234 if e1.regulatory != NX_REG_APPROVED { return 175 } 235 if e1.name_ptr[0] as nx_int != 0x74 { return 176 } // 't' 236 if e1.name_ptr[4] as nx_int != 0x31 { return 177 } // '1' 237 // Lookup test2 by id 101 238 let e2: *AdulterantEntry = nx_chem_adulterant_entry_by_id(db, 101) 239 if (e2 as nx_int) == 0 { return 178 } 240 if e2.regulatory != NX_REG_BANNED { return 179 } 241 return 0 242} 243 244// ================================================================= 245// N -- C10.0 multi-halogen entries: clenbuterol (2 Cl -> sig 3), 246// 2C-B (1 Br -> sig 2), salbutamol (no halogen -> sig 0) 247// ================================================================= 248func n_new_halogen_sigs() -> nx_int { 249 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 250 let e_salb: *AdulterantEntry = ((db.entries as nx_int) + (21 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 251 if e_salb.halogen_sig != 0 { return 161 } 252 let e_clen: *AdulterantEntry = ((db.entries as nx_int) + (22 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 253 if e_clen.halogen_sig != 3 { return 162 } // 2 Cl -> multi-halogen sig 254 let e_2cb: *AdulterantEntry = ((db.entries as nx_int) + (23 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 255 if e_2cb.halogen_sig != 2 { return 163 } // 1 Br -> Br 1:1 sig 256 return 0 257} 258 259// ================================================================= 260// M -- C7.1 load RT calibration from CSV file 261// ================================================================= 262func m_load_rt_calibration() -> nx_int { 263 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 264 // Build CSV text in memory 265 // "# RT calibration\n4 740.0 30.0\n1 45.0 15.0\n" 266 let src: *u8 = sys_mmap(128) 267 src[0] = 0x23; src[1] = 0x20; src[2] = 0x52; src[3] = 0x54 268 src[4] = 0x0A 269 src[5] = 0x34 // '4' 270 src[6] = 0x20 271 src[7] = 0x37; src[8] = 0x34; src[9] = 0x30; src[10] = 0x2E; src[11] = 0x30 272 src[12] = 0x20 273 src[13] = 0x33; src[14] = 0x30; src[15] = 0x2E; src[16] = 0x30 274 src[17] = 0x0A 275 src[18] = 0x31 // '1' 276 src[19] = 0x20 277 src[20] = 0x34; src[21] = 0x35; src[22] = 0x2E; src[23] = 0x30 278 src[24] = 0x20 279 src[25] = 0x31; src[26] = 0x35; src[27] = 0x2E; src[28] = 0x30 280 src[29] = 0x0A 281 let n_src: nx_int = 30 282 // Write to disk 283 let path: *u8 = sys_mmap(64) 284 path[0] = 0x2F; path[1] = 0x74; path[2] = 0x6D; path[3] = 0x70 285 path[4] = 0x2F; path[5] = 0x6E; path[6] = 0x78; path[7] = 0x5F 286 path[8] = 0x72; path[9] = 0x74; path[10] = 0x5F 287 path[11] = 0x63; path[12] = 0x61; path[13] = 0x6C; path[14] = 0x2E 288 path[15] = 0x63; path[16] = 0x73; path[17] = 0x76 289 path[18] = 0 290 let nw: nx_int = nx_chem_write_file(path, src, n_src) 291 if nw != n_src { return 151 } 292 // Load calibration 293 let n_loaded: nx_int = nx_chem_load_rt_calibration(db, path) 294 if n_loaded != 2 { return 152 } 295 // Verify sibutramine (id 4) has ref_rt = 740000 ms (740 sec) 296 let e4: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 297 if e4.ref_rt_q3 != 740000 { return 153 } 298 if e4.rt_tol_q3 != 30000 { return 154 } 299 // Verify DMAA (id 1) has ref_rt = 45000 ms (45 sec) 300 let e1: *AdulterantEntry = ((db.entries as nx_int) + (1 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 301 if e1.ref_rt_q3 != 45000 { return 155 } 302 if e1.rt_tol_q3 != 15000 { return 156 } 303 return 0 304} 305 306// ================================================================= 307// LAB-FACING END-TO-END DEMO: 308// Simulate a lab analyst feeding in 4 LC-MS peaks from a suspect 309// supplement and producing a verdict report. 310// ================================================================= 311func run_lab_demo() -> nx_int { 312 println("" as *u8) 313 println("==================================================================" as *u8) 314 println(" SUPPLEMENT ADULTERANT DETECTION REPORT (LC-MS pipeline demo)" as *u8) 315 println("==================================================================" as *u8) 316 println(" Sample : SUSPECT-2026-001 (pre-workout powder)" as *u8) 317 println(" Method : LC-ESI(+)-MS, 5 ppm tolerance" as *u8) 318 println(" Substrate : nx_chem bits-up sovereign analytical-chem stack" as *u8) 319 println(" Pipeline : C2.1 SMILES -> C2.8a [M+H]+ -> 5ppm DB lookup" as *u8) 320 println("" as *u8) 321 println(" Observed peaks:" as *u8) 322 let db: *AdulterantDB = nx_chem_adulterant_db_seed() 323 // 4 synthetic peaks: use DB-computed m/z to ensure exact match 324 let e_sibutramine: *AdulterantEntry = ((db.entries as nx_int) + (4 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 325 let e_dmaa: *AdulterantEntry = ((db.entries as nx_int) + (1 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 326 let e_caffeine: *AdulterantEntry = ((db.entries as nx_int) + (5 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 327 let e_ephedrine: *AdulterantEntry = ((db.entries as nx_int) + (0 * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 328 let peaks: *nx_int = (sys_mmap((4 * 8) as i64)) as *nx_int 329 peaks[0] = e_sibutramine.mh_plus_q4 + 5 // small noise offset 330 peaks[1] = e_dmaa.mh_plus_q4 331 peaks[2] = e_caffeine.mh_plus_q4 332 peaks[3] = e_ephedrine.mh_plus_q4 333 var n_banned: nx_int = 0 334 var n_restricted: nx_int = 0 335 var n_unknown: nx_int = 0 336 var pk: nx_int = 0 337 while pk < 4 { 338 let mz: nx_int = peaks[pk] 339 let outs: *MatchResult = (sys_mmap((4 * NX_MATCH_RESULT_BYTES) as i64)) as *MatchResult 340 let nm: nx_int = nx_chem_adulterant_db_lookup_mh_plus(db, mz, 5, outs, 4) 341 if nm == 0 { 342 let _u1: i64 = print(" m/z " as *u8) 343 let _u2: i64 = print_q4_mass(mz) 344 let _u3: i64 = println(" -> NO MATCH (unidentified)" as *u8) 345 n_unknown = n_unknown + 1 346 } 347 if nm > 0 { 348 var mi: nx_int = 0 349 while mi < nm { 350 let rr: *MatchResult = ((outs as nx_int) + (mi * NX_MATCH_RESULT_BYTES)) as *MatchResult 351 let _r: nx_int = nx_chem_adulterant_report_match(mz, db, rr) 352 let _cite_pad: i64 = print(" cite: " as *u8) 353 let _cite: i64 = println(nx_chem_adulterant_citation(rr.entry_id)) 354 let ee: *AdulterantEntry = ((db.entries as nx_int) + (rr.entry_id * NX_ADULTERANT_ENTRY_BYTES)) as *AdulterantEntry 355 if ee.regulatory == NX_REG_BANNED { n_banned = n_banned + 1 } 356 if ee.regulatory == NX_REG_RESTRICTED { n_restricted = n_restricted + 1 } 357 mi = mi + 1 358 } 359 } 360 pk = pk + 1 361 } 362 println("" as *u8) 363 println(" VERDICT:" as *u8) 364 let _v1: i64 = print(" Banned ingredients detected : " as *u8) 365 let _v2: i64 = print_i64(n_banned as i64) 366 let _v3: i64 = println("" as *u8) 367 let _v4: i64 = print(" Restricted ingredients : " as *u8) 368 let _v5: i64 = print_i64(n_restricted as i64) 369 let _v6: i64 = println("" as *u8) 370 let _v7: i64 = print(" Unidentified peaks : " as *u8) 371 let _v8: i64 = print_i64(n_unknown as i64) 372 let _v9: i64 = println("" as *u8) 373 if n_banned > 0 { 374 println(" *** RECOMMENDATION: REJECT -- contains banned ingredient(s) ***" as *u8) 375 } 376 if n_banned == 0 { 377 if n_restricted > 0 { 378 println(" RECOMMENDATION: review label claim vs restricted ingredient list" as *u8) 379 } 380 if n_restricted == 0 { 381 println(" RECOMMENDATION: no banned/restricted ingredients in matched peaks" as *u8) 382 } 383 } 384 println("==================================================================" as *u8) 385 return 0 386} 387 388func main() -> nx_exit { 389 println("=== nx_chem_adulterant_db -- C4.0 KAT: seed DB + lookup pipeline ===" as *u8) 390 391 let ra: nx_int = a_seed_count() 392 if ra != 0 { println("A seed_count FAIL" as *u8); return ra } 393 println("A seed_count PASS 33 reference adulterants populated" as *u8) 394 395 let rb: nx_int = b_sibutramine_signature() 396 if rb != 0 { println("B sibutramine_signature FAIL" as *u8); return rb } 397 println("B sibutramine_sig PASS id=4 has Cl halogen sig + BANNED status" as *u8) 398 399 let rc: nx_int = c_caffeine_signature() 400 if rc != 0 { println("C caffeine_signature FAIL" as *u8); return rc } 401 println("C caffeine_sig PASS id=5 has no halogen sig + APPROVED status" as *u8) 402 403 let rd: nx_int = d_lookup_sibutramine() 404 if rd != 0 { println("D lookup_sibutramine FAIL" as *u8); return rd } 405 println("D lookup_sibutramine PASS exact m/z lookup returns sibutramine match" as *u8) 406 407 let re: nx_int = e_lookup_no_match() 408 if re != 0 { println("E lookup_no_match FAIL" as *u8); return re } 409 println("E lookup_no_match PASS off-mass m/z returns zero matches" as *u8) 410 411 let rf: nx_int = f_lookup_3ppm_offset() 412 if rf != 0 { println("F lookup_3ppm_offset FAIL" as *u8); return rf } 413 println("F lookup_3ppm_offset PASS 3 ppm offset within 5 ppm tolerance" as *u8) 414 415 let rg: nx_int = g_lookup_10ppm_offset() 416 if rg != 0 { println("G lookup_10ppm_offset FAIL" as *u8); return rg } 417 println("G lookup_10ppm_offset PASS 10 ppm offset OUTSIDE 5 ppm tolerance (correctly rejected)" as *u8) 418 419 let rh: nx_int = h_distinct_mz() 420 if rh != 0 { println("H distinct_mz FAIL (seed data has m/z collision)" as *u8); return rh } 421 println("H distinct_mz PASS no accidental m/z collisions in seed" as *u8) 422 423 let ri: nx_int = i_rt_lookup_no_ref_rt() 424 if ri != 0 { println("I rt_lookup_no_ref_rt FAIL" as *u8); return ri } 425 println("I rt_no_ref_rt PASS RT filter no-op when ref_rt unset (mass-only)" as *u8) 426 427 let rj: nx_int = j_rt_off_rejected() 428 if rj != 0 { println("J rt_off_rejected FAIL" as *u8); return rj } 429 println("J rt_off_rejected PASS off-RT same-mass peak correctly rejected" as *u8) 430 431 let rk: nx_int = k_rt_on_matches() 432 if rk != 0 { println("K rt_on_matches FAIL" as *u8); return rk } 433 println("K rt_on_matches PASS on-RT (within tolerance) matches" as *u8) 434 435 let rl: nx_int = l_rt_zero_observed_bypasses() 436 if rl != 0 { println("L rt_zero_observed FAIL" as *u8); return rl } 437 println("L rt_zero_observed PASS obs_rt=0 bypasses RT filter (graceful)" as *u8) 438 439 let rm: nx_int = m_load_rt_calibration() 440 if rm != 0 { println("M load_rt_calibration FAIL" as *u8); return rm } 441 println("M load_rt_calibration PASS CSV file -> ref_rt + tol populated in DB" as *u8) 442 443 let rn: nx_int = n_new_halogen_sigs() 444 if rn != 0 { println("N new_halogen_sigs FAIL" as *u8); return rn } 445 println("N new_halogen_sigs PASS salbutamol=0 clenbuterol=3(multi-Cl) 2C-B=2(Br)" as *u8) 446 447 let ro: nx_int = o_load_compounds() 448 if ro != 0 { println("O load_compounds FAIL" as *u8); return ro } 449 println("O load_compounds PASS pipe-separated TSV -> 2 compounds loaded into DB" as *u8) 450 451 let _demo: nx_int = run_lab_demo() 452 453 println("" as *u8) 454 println("=== C4.0 substrate milestone PASS ===" as *u8) 455 println(" AdulterantDB struct + 8 reference compounds seeded via SMILES parsing" as *u8) 456 println(" Lookup primitive: 5 ppm window m/z -> matching reference entries" as *u8) 457 println(" End-to-end demo: 4-peak synthetic LC-MS -> verdict report with REJECT" as *u8) 458 println(" recommendation when banned ingredients detected" as *u8) 459 println(" FIRST USABLE MILESTONE: a lab analyst could read this output and act" as *u8) 460 println("" as *u8) 461 println(" Composes: C2.1 SMILES parse, C2.3a implicit-H, C2.8a [M+H]+, C2.8b" as *u8) 462 println(" halogen sig + isotope pattern. End-to-end SMILES -> verdict." as *u8) 463 println("" as *u8) 464 println(" Honest gaps: persistence (memory-only), retention-time matching not yet," as *u8) 465 println(" complex-SMILES adulterants (sildenafil, tadalafil) deferred" as *u8) 466 println(" until parser handles their aromatic+saturated mixed rings." as *u8) 467 return 0 468}