code wiki / _hdl_build / nx_adnet_reconcile_gate.nx

nx_adnet_reconcile_gate.nx source

↩ module page · 98 lines · 5347 B

1// nx_adnet_reconcile_gate.nx -- GATE for the spend reconciler (nx_adnet_reconcile). 2// A reconciler is dangerous in two directions and both are teeth here: 3// * DATA LOSS -- it must preserve comments, blanks and rows it cannot compute, BYTE-IDENTICAL. A 4// reconciler that drops what it cannot parse is a data-loss bug wearing a maintenance-task costume. 5// * SILENT REVIVAL -- an UNMEASURABLE spend must leave the old value alone, never write 0. Zeroing an 6// exhausted campaign restarts spending against a budget that is already gone, which is the single 7// worst thing this organ could do. 8// expect_exit: 0 license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "_hdl_build/nx_adnet_reconcile.nx" 11import "nx_gate_verdict.nx" 12 13func tr_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i } 14func tr_puts(s: *u8) -> i64 { sys_write(1, s, tr_slen(s)); return 0 } 15func tr_pn(v: i64) -> i64 { 16 let b: *u8 = sys_mmap(32) 17 if v == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 } 18 var n: i64 = 0 19 var x: i64 = v 20 while x > 0 { b[n] = ((x - (x / 10) * 10) + 48) as u8; n = n + 1; x = x / 10 } 21 let r: *u8 = sys_mmap(32) 22 var i: i64 = 0 23 while i < n { r[i] = b[n - 1 - i]; i = i + 1 } 24 sys_write(1, r, n) 25 return 0 26} 27func tr_has(buf: *u8, n: i64, pat: *u8) -> i64 { 28 let pl: i64 = tr_slen(pat) 29 if pl == 0 { return 0 } 30 if pl > n { return 0 } 31 var i: i64 = 0 32 while i <= n - pl { 33 var k: i64 = 0 34 var ok: i64 = 1 35 while k < pl { if buf[i + k] != pat[k] { ok = 0; break } k = k + 1 } 36 if ok == 1 { return 1 } 37 i = i + 1 38 } 39 return 0 40} 41func tr_check(name: *u8, cond: i64) -> i64 { 42 if cond == 1 { tr_puts(" PASS " as *u8) } else { tr_puts(" FAIL " as *u8) } 43 tr_puts(name); tr_puts("\n" as *u8) 44 return cond 45} 46 47func main() -> i64 { 48 tr_puts("=== nx_adnet_reconcile_gate ===\n" as *u8) 49 var pass: i64 = 0 50 var total: i64 = 0 51 let out: *u8 = sys_mmap(8192) 52 53 // ha-video priced 5000/100; ha-world DELIBERATELY unpriced -> spend UNMEASURABLE 54 let rates: *u8 = "ha-video\t5000\t100\t-1\n" as *u8 55 let slog: *u8 = "ha-video\nha-video\nha-video\nha-video\nha-world\n" as *u8 56 let vlog: *u8 = "ha-video\n" as *u8 57 let clog: *u8 = "ha-video\n" as *u8 58 // camp rows carry a STALE spend of 9999 so a refresh is visible, and ha-world carries 4242 which must SURVIVE 59 let camps: *u8 = "# spend is owned by the reconciler beat\nha-video\tacme\t/synth/v.png\t1000\t2000\t5000\tlive\t9999\nha-world\tacme\t/synth/w.png\t1000\t2000\t5000\tlive\t4242\n" as *u8 60 let rl: i64 = tr_slen(rates) 61 let sl: i64 = tr_slen(slog) 62 let vl: i64 = tr_slen(vlog) 63 let cl: i64 = tr_slen(clog) 64 let cn: i64 = tr_slen(camps) 65 66 let n: i64 = arec_refresh(camps, cn, rates, rl, slog, sl, vlog, vl, clog, cl, out, 8192) 67 pass = pass + tr_check("conf emitted" as *u8, n > 0); total = total + 1 68 69 // measurable: viewable=1 clicks=1 cpm=5000 cpc=100 -> (1*5000)/1000 + 100 = 105 70 pass = pass + tr_check("priced campaign spend REFRESHED to 105" as *u8, tr_has(out, n, "live\t105" as *u8)); total = total + 1 71 pass = pass + tr_check("stale 9999 is GONE" as *u8, tr_has(out, n, "9999" as *u8) == 0); total = total + 1 72 73 // unmeasurable: must survive untouched, NOT be zeroed 74 pass = pass + tr_check("UNMEASURABLE spend left alone (4242 survives)" as *u8, tr_has(out, n, "4242" as *u8)); total = total + 1 75 pass = pass + tr_check("unmeasurable was NOT zeroed (no 'live\\t0')" as *u8, tr_has(out, n, "live\t0\n" as *u8) == 0); total = total + 1 76 77 // structure preserved 78 pass = pass + tr_check("comment row preserved" as *u8, tr_has(out, n, "# spend is owned by the reconciler beat" as *u8)); total = total + 1 79 pass = pass + tr_check("both campaigns still present" as *u8, tr_has(out, n, "ha-video" as *u8) + tr_has(out, n, "ha-world" as *u8) == 2); total = total + 1 80 pass = pass + tr_check("advertiser column preserved verbatim" as *u8, tr_has(out, n, "acme" as *u8)); total = total + 1 81 pass = pass + tr_check("creative column preserved verbatim" as *u8, tr_has(out, n, "/synth/v.png" as *u8)); total = total + 1 82 83 // idempotence: reconciling the OUTPUT again must be stable (a beat runs forever) 84 let out2: *u8 = sys_mmap(8192) 85 let n2: i64 = arec_refresh(out, n, rates, rl, slog, sl, vlog, vl, clog, cl, out2, 8192) 86 pass = pass + tr_check("IDEMPOTENT: second pass still 105" as *u8, tr_has(out2, n2, "live\t105" as *u8)); total = total + 1 87 pass = pass + tr_check("IDEMPOTENT: second pass still preserves 4242" as *u8, tr_has(out2, n2, "4242" as *u8)); total = total + 1 88 89 tr_puts("pass=" as *u8); tr_pn(pass); tr_puts(" fail=" as *u8); tr_pn(total - pass); tr_puts("\n" as *u8) 90 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 91 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 92 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 93 let ctr__dry: *i64 = gv_ctr() 94 ctr__dry[0] = pass 95 ctr__dry[1] = total 96 let rc__dry: i64 = gv_verdict("ADNET-RECONCILE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 97 sys_exit(rc__dry) 98 return rc__dry 99}