code wiki / _hdl_build / nx_apm_collect_gate.nx

nx_apm_collect_gate.nx source

↩ module page · 111 lines · 6756 B

1// nx_apm_collect_gate.nx -- SOVEREIGN gate for the internal-HTTP APM collector. 2// 3// Spawns real mock daemons (nx_apm_mock, self-terminating) on loopback and proves ac_burst's four verdicts 4// against ground truth -- each test prints its MEASURED numbers (no overclaim: the operator reads the raw 5// stats, not a curated "GREEN"): 6// T1 NEGATIVE CONTROL -- a healthy fast daemon must be GREEN, fully served, nothing flagged. 7// T2 DETECTION -- a daemon that SERIALIZES (300ms/req) must, under 8 concurrent probes, show a 8// stall and max >= ~2400ms = the "tabs don't load" wedge, caught. 9// T3 LIAR-KILL -- an ABSENT daemon (no listener) must be DOWN with oks=0, never GREEN. 10// T4 GRACEFUL DEGRADE -- a daemon slower than the probe timeout must time out (~1s) not hang forever. 11// T5 ARTIFACT-IMMUNITY -- a daemon that sends FAST then HOLDS the socket open (keep-alive/idle) must be 12// GREEN (ttfb fast) with slowclose>0 -- NOT a false wedge. This is THE fix: the 13// live :8791/vroom "20s" was exactly this (ttfb~0, total~20-25s), an artifact. 14// 15// Requires /tmp/nx_apm_mock.sov.elf built first. Per-test reap; no kill primitive needed. license_tier: ORIGINAL 16import "nx_syscalls.nx" 17import "nx_apm_collect.nx" // ac_burst + AC_R_* + ac_n 18import "nx_gate_verdict.nx" 19 20const GE_MOCK: *u8 = "_offc/nx_apm_mock.elf" 21 22func ge_uw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 23func ge_wn(v: i64) -> i64 { let b: *u8 = sys_mmap(24); let e: i64 = ac_n(b, 0, v); sys_write(1, b, e); return 0 } 24func ge_itoa(v: i64) -> *u8 { let b: *u8 = sys_mmap(24); let e: i64 = ac_n(b, 0, v); b[e] = 0 as u8; return b } 25 26// fork + execve the mock with (port, delay_ms, hold_ms, max_reqs) as string args; returns pid. 27func ge_spawn_mock(port: i64, delay: i64, hold: i64, maxr: i64) -> i64 { 28 let pid: i64 = sys_fork() 29 if pid == 0 { 30 let av: *i64 = sys_mmap(8 * 6) as *i64 31 av[0] = GE_MOCK as i64 32 av[1] = ge_itoa(port) as i64 33 av[2] = ge_itoa(delay) as i64 34 av[3] = ge_itoa(hold) as i64 35 av[4] = ge_itoa(maxr) as i64 36 av[5] = 0 37 let ev: *i64 = sys_mmap(8) as *i64; ev[0] = 0 38 sys_execve(GE_MOCK, av, ev); sys_exit(127) 39 } 40 return pid 41} 42 43func main(argc: i64, argv: *i64) -> i64 { 44 var pass: i64 = 0; var total: i64 = 0 45 let out: *i64 = sys_mmap(8 * 12) as *i64 46 let rp: *i64 = sys_mmap(16) as *i64 47 let epoch: i64 = sys_now_realtime_sec() 48 49 // ---- T1: healthy fast daemon (NEGATIVE CONTROL) ---- 50 let pA: i64 = ge_spawn_mock(18091, 0, 0, 8) 51 sys_sleep_ms(300) 52 let cA: i64 = ac_burst(18091, "/" as *u8, "mock-fast" as *u8, 8, 22, epoch, 0x7f000001, out) 53 total = total + 1 54 var okA: i64 = 0 55 if cA == AC_R_GREEN { if out[3] == 8 { if out[4] == 0 { okA = 1 } } } 56 if okA == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) } 57 ge_uw("T1 healthy(neg-control): code=" as *u8); ge_wn(cA); ge_uw(" oks=" as *u8); ge_wn(out[3]); ge_uw(" p50=" as *u8); ge_wn(out[0]); ge_uw(" max=" as *u8); ge_wn(out[2]); ge_uw("ms stalls=" as *u8); ge_wn(out[4]); ge_uw(" (want GREEN, oks=8, stalls=0)\n" as *u8) 58 sys_wait4(pA, rp, 0) 59 60 // ---- T2: serializing daemon under 8 concurrent probes (DETECTION) ---- 61 let pB: i64 = ge_spawn_mock(18092, 300, 0, 8) 62 sys_sleep_ms(300) 63 let cB: i64 = ac_burst(18092, "/library" as *u8, "mock-wedge" as *u8, 8, 22, epoch, 0x7f000001, out) 64 total = total + 1 65 var okB: i64 = 0 66 if cB >= AC_R_AMBER { if out[4] > 0 { if out[2] >= 2000 { okB = 1 } } } 67 if okB == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) } 68 ge_uw("T2 serial-wedge(detect): code=" as *u8); ge_wn(cB); ge_uw(" p50=" as *u8); ge_wn(out[0]); ge_uw(" max=" as *u8); ge_wn(out[2]); ge_uw("ms stalls=" as *u8); ge_wn(out[4]); ge_uw(" (want >=AMBER, stalls>0, max>=2000ms)\n" as *u8) 69 sys_wait4(pB, rp, 0) 70 71 // ---- T3: absent daemon, no listener (LIAR-KILL) ---- 72 let cC: i64 = ac_burst(18094, "/" as *u8, "mock-absent" as *u8, 4, 22, epoch, 0x7f000001, out) 73 total = total + 1 74 var okC: i64 = 0 75 if cC == AC_R_DOWN { if out[3] == 0 { okC = 1 } } 76 if okC == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) } 77 ge_uw("T3 absent(liar-kill): code=" as *u8); ge_wn(cC); ge_uw(" oks=" as *u8); ge_wn(out[3]); ge_uw(" down=" as *u8); ge_wn(out[6]); ge_uw(" (want DOWN, oks=0)\n" as *u8) 78 79 // ---- T4: daemon slower than the probe timeout (GRACEFUL DEGRADATION) ---- 80 let pD: i64 = ge_spawn_mock(18093, 3000, 0, 1) 81 sys_sleep_ms(300) 82 let cD: i64 = ac_burst(18093, "/" as *u8, "mock-hang" as *u8, 1, 1, epoch, 0x7f000001, out) 83 total = total + 1 84 var okD: i64 = 0 85 if cD == AC_R_RED { if out[5] >= 1 { if out[2] < 3000 { okD = 1 } } } 86 if okD == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) } 87 ge_uw("T4 hang(timeout/grace): code=" as *u8); ge_wn(cD); ge_uw(" timeouts=" as *u8); ge_wn(out[5]); ge_uw(" max=" as *u8); ge_wn(out[2]); ge_uw("ms (want RED, timeouts>=1, max<3000ms i.e. it gave up at ~1s)\n" as *u8) 88 sys_wait4(pD, rp, 0) 89 90 // ---- T5: fast-then-HOLD daemon = keep-alive/idle-close ARTIFACT (the live :8791 + vroom :8446 case) ---- 91 let pE: i64 = ge_spawn_mock(18095, 0, 4000, 1) 92 sys_sleep_ms(300) 93 let cE: i64 = ac_burst(18095, "/" as *u8, "mock-artifact" as *u8, 1, 22, epoch, 0x7f000001, out) 94 total = total + 1 95 var okE: i64 = 0 96 if cE == AC_R_GREEN { if out[9] >= 1 { if out[2] < 2000 { if out[8] >= 3000 { okE = 1 } } } } 97 if okE == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) } 98 ge_uw("T5 fast-then-hold(artifact-immune): code=" as *u8); ge_wn(cE); ge_uw(" ttfb_max=" as *u8); ge_wn(out[2]); ge_uw("ms total_max=" as *u8); ge_wn(out[8]); ge_uw("ms slowclose=" as *u8); ge_wn(out[9]); ge_uw(" (want GREEN, ttfb<2000, total>=3000, slowclose>=1)\n" as *u8) 99 sys_wait4(pE, rp, 0) 100 101 ge_uw("=== nx_apm_collect_gate " as *u8); ge_wn(pass); ge_uw("/" as *u8); ge_wn(total) 102 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 103 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 104 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 105 let ctr__dry: *i64 = gv_ctr() 106 ctr__dry[0] = pass 107 ctr__dry[1] = total 108 let rc__dry: i64 = gv_verdict("APM-COLLECT-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 109 sys_exit(rc__dry) 110 return rc__dry 111}