code wiki / _hdl_build / nx_apm_collect_gate.nx
nx_apm_collect_gate.nx source
↩ module page · 103 lines · 6271 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
18
19const GE_MOCK: *u8 = "_offc/nx_apm_mock.elf"
20
21func 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 }
22func 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 }
23func 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 }
24
25// fork + execve the mock with (port, delay_ms, hold_ms, max_reqs) as string args; returns pid.
26func ge_spawn_mock(port: i64, delay: i64, hold: i64, maxr: i64) -> i64 {
27 let pid: i64 = sys_fork()
28 if pid == 0 {
29 let av: *i64 = sys_mmap(8 * 6) as *i64
30 av[0] = GE_MOCK as i64
31 av[1] = ge_itoa(port) as i64
32 av[2] = ge_itoa(delay) as i64
33 av[3] = ge_itoa(hold) as i64
34 av[4] = ge_itoa(maxr) as i64
35 av[5] = 0
36 let ev: *i64 = sys_mmap(8) as *i64; ev[0] = 0
37 sys_execve(GE_MOCK, av, ev); sys_exit(127)
38 }
39 return pid
40}
41
42func main(argc: i64, argv: *i64) -> i64 {
43 var pass: i64 = 0; var total: i64 = 0
44 let out: *i64 = sys_mmap(8 * 12) as *i64
45 let rp: *i64 = sys_mmap(16) as *i64
46 let epoch: i64 = sys_now_realtime_sec()
47
48 // ---- T1: healthy fast daemon (NEGATIVE CONTROL) ----
49 let pA: i64 = ge_spawn_mock(18091, 0, 0, 8)
50 sys_sleep_ms(300)
51 let cA: i64 = ac_burst(18091, "/" as *u8, "mock-fast" as *u8, 8, 22, epoch, 0x7f000001, out)
52 total = total + 1
53 var okA: i64 = 0
54 if cA == AC_R_GREEN { if out[3] == 8 { if out[4] == 0 { okA = 1 } } }
55 if okA == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) }
56 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)
57 sys_wait4(pA, rp, 0)
58
59 // ---- T2: serializing daemon under 8 concurrent probes (DETECTION) ----
60 let pB: i64 = ge_spawn_mock(18092, 300, 0, 8)
61 sys_sleep_ms(300)
62 let cB: i64 = ac_burst(18092, "/library" as *u8, "mock-wedge" as *u8, 8, 22, epoch, 0x7f000001, out)
63 total = total + 1
64 var okB: i64 = 0
65 if cB >= AC_R_AMBER { if out[4] > 0 { if out[2] >= 2000 { okB = 1 } } }
66 if okB == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) }
67 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)
68 sys_wait4(pB, rp, 0)
69
70 // ---- T3: absent daemon, no listener (LIAR-KILL) ----
71 let cC: i64 = ac_burst(18094, "/" as *u8, "mock-absent" as *u8, 4, 22, epoch, 0x7f000001, out)
72 total = total + 1
73 var okC: i64 = 0
74 if cC == AC_R_DOWN { if out[3] == 0 { okC = 1 } }
75 if okC == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) }
76 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)
77
78 // ---- T4: daemon slower than the probe timeout (GRACEFUL DEGRADATION) ----
79 let pD: i64 = ge_spawn_mock(18093, 3000, 0, 1)
80 sys_sleep_ms(300)
81 let cD: i64 = ac_burst(18093, "/" as *u8, "mock-hang" as *u8, 1, 1, epoch, 0x7f000001, out)
82 total = total + 1
83 var okD: i64 = 0
84 if cD == AC_R_RED { if out[5] >= 1 { if out[2] < 3000 { okD = 1 } } }
85 if okD == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) }
86 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)
87 sys_wait4(pD, rp, 0)
88
89 // ---- T5: fast-then-HOLD daemon = keep-alive/idle-close ARTIFACT (the live :8791 + vroom :8446 case) ----
90 let pE: i64 = ge_spawn_mock(18095, 0, 4000, 1)
91 sys_sleep_ms(300)
92 let cE: i64 = ac_burst(18095, "/" as *u8, "mock-artifact" as *u8, 1, 22, epoch, 0x7f000001, out)
93 total = total + 1
94 var okE: i64 = 0
95 if cE == AC_R_GREEN { if out[9] >= 1 { if out[2] < 2000 { if out[8] >= 3000 { okE = 1 } } } }
96 if okE == 1 { pass = pass + 1; ge_uw("[PASS] " as *u8) } else { ge_uw("[FAIL] " as *u8) }
97 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)
98 sys_wait4(pE, rp, 0)
99
100 ge_uw("=== nx_apm_collect_gate " as *u8); ge_wn(pass); ge_uw("/" as *u8); ge_wn(total)
101 if pass == total { ge_uw(" GREEN\n" as *u8); return 0 }
102 ge_uw(" RED\n" as *u8); return 1
103}