code wiki / _hdl_build / nx_adnet_invoice_gate.nx
nx_adnet_invoice_gate.nx source
↩ module page · 131 lines · 8336 B
1// nx_adnet_invoice_gate.nx -- GATE for the billing pipeline (nx_adnet_invoice).
2// Independent re-derivation over fixture journals, not a call into the code under test to describe itself.
3// The teeth that matter are the REFUSALS -- a biller is dangerous in the direction of over-charging:
4// * an ad with NO rate row must emit an explicit REFUSED line, never a zero-priced or omitted one
5// * an ad measured but never viewable must bill 0, not its served count
6// * a rate card with a malformed number must REFUSE, not parse-to-zero
7// * SPEND (the number a budget ceiling consumes) must be UNMEASURABLE rather than 0 when unpriced --
8// assuming zero spend is exactly how an exhausted campaign keeps serving
9// expect_exit: 0 license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "_hdl_build/nx_adnet_invoice.nx"
12import "nx_gate_verdict.nx"
13
14func ti_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i }
15func ti_puts(s: *u8) -> i64 { sys_write(1, s, ti_slen(s)); return 0 }
16func ti_pn(v: i64) -> i64 {
17 let b: *u8 = sys_mmap(32)
18 if v == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 }
19 var n: i64 = 0
20 var x: i64 = v
21 while x > 0 { b[n] = ((x - (x / 10) * 10) + 48) as u8; n = n + 1; x = x / 10 }
22 let r: *u8 = sys_mmap(32)
23 var i: i64 = 0
24 while i < n { r[i] = b[n - 1 - i]; i = i + 1 }
25 sys_write(1, r, n)
26 return 0
27}
28func ti_has(buf: *u8, n: i64, pat: *u8) -> i64 {
29 let pl: i64 = ti_slen(pat)
30 if pl == 0 { return 0 }
31 if pl > n { return 0 }
32 var i: i64 = 0
33 while i <= n - pl {
34 var k: i64 = 0
35 var ok: i64 = 1
36 while k < pl { if buf[i + k] != pat[k] { ok = 0; break } k = k + 1 }
37 if ok == 1 { return 1 }
38 i = i + 1
39 }
40 return 0
41}
42func ti_check(name: *u8, cond: i64) -> i64 {
43 if cond == 1 { ti_puts(" PASS " as *u8) } else { ti_puts(" FAIL " as *u8) }
44 ti_puts(name); ti_puts("\n" as *u8)
45 return cond
46}
47
48func main() -> i64 {
49 ti_puts("=== nx_adnet_invoice_gate ===\n" as *u8)
50 var pass: i64 = 0
51 var total: i64 = 0
52 let buf: *u8 = sys_mmap(8192)
53
54 // fixtures: ha-video priced, ha-world DELIBERATELY unpriced, ha-bad has a malformed cpm
55 let rates: *u8 = "# id\tcpm_milli\tcpc_milli\tcap_milli\nha-video\t5000\t100\t-1\nha-bad\tzzz\t100\t-1\n" as *u8
56 let inv: *u8 = "@host\tnishifamily.com\nha-video\tNishi Video\t/synth/v.png\t/video\tany\t1\nha-world\tNishi World\t/synth/w.png\t/world\tany\t1\n" as *u8
57 let slog: *u8 = "ha-video\nha-video\nha-video\nha-video\nha-world\n" as *u8
58 let vlog: *u8 = "ha-video\n" as *u8
59 let clog: *u8 = "ha-video\n" as *u8
60 let rl: i64 = ti_slen(rates)
61 let il: i64 = ti_slen(inv)
62 let sl: i64 = ti_slen(slog)
63 let vl: i64 = ti_slen(vlog)
64 let cl: i64 = ti_slen(clog)
65
66 // ---- rate card parsing ----
67 pass = pass + ti_check("rate lookup: cpm found" as *u8, ainv_rate(rates, rl, "ha-video" as *u8, 1) == 5000); total = total + 1
68 pass = pass + ti_check("rate lookup: cpc found" as *u8, ainv_rate(rates, rl, "ha-video" as *u8, 2) == 100); total = total + 1
69 pass = pass + ti_check("unpriced ad -> rate REFUSED" as *u8, ainv_rate(rates, rl, "ha-world" as *u8, 1) == 0 - 1); total = total + 1
70 pass = pass + ti_check("malformed rate -> REFUSED not zero" as *u8, ainv_rate(rates, rl, "ha-bad" as *u8, 1) == 0 - 1); total = total + 1
71
72 // ---- one priced line: served=4 viewable=1 clicks=1 cpm=5000 -> (1*5000)/1000 + 100 = 105 ----
73 let n1: i64 = ainv_line_for(rates, rl, slog, sl, vlog, vl, clog, cl, "ha-video" as *u8, buf, 8192)
74 pass = pass + ti_check("priced ad -> line emitted" as *u8, n1 > 0); total = total + 1
75 pass = pass + ti_check("bills VIEWABLE=1 not SERVED=4 (due 105)" as *u8, ti_has(buf, n1, "due_milli=105" as *u8)); total = total + 1
76 pass = pass + ti_check("served=4 reported honestly" as *u8, ti_has(buf, n1, "served=4" as *u8)); total = total + 1
77 pass = pass + ti_check("delivery ratio 250 permille" as *u8, ti_has(buf, n1, "deliv_permille=250" as *u8)); total = total + 1
78
79 // ---- the refusal that protects the client ----
80 let n2: i64 = ainv_line_for(rates, rl, slog, sl, vlog, vl, clog, cl, "ha-world" as *u8, buf, 8192)
81 pass = pass + ti_check("unpriced ad -> REFUSED line, not omitted" as *u8, ti_has(buf, n2, "due_milli=REFUSED" as *u8)); total = total + 1
82 pass = pass + ti_check("unpriced ad -> reason is named" as *u8, ti_has(buf, n2, "reason=no-rate-row" as *u8)); total = total + 1
83
84 // ---- full report covers EVERY inventory ad, priced or not ----
85 let n3: i64 = ainv_report(inv, il, rates, rl, slog, sl, vlog, vl, clog, cl, buf, 8192)
86 pass = pass + ti_check("report covers the priced ad" as *u8, ti_has(buf, n3, "id=ha-video" as *u8)); total = total + 1
87 pass = pass + ti_check("report covers the UNPRICED ad too" as *u8, ti_has(buf, n3, "id=ha-world" as *u8)); total = total + 1
88 pass = pass + ti_check("report skips the @host directive row" as *u8, ti_has(buf, n3, "id=@host" as *u8) == 0); total = total + 1
89
90 // ---- SPEND: the number a budget ceiling consumes ----
91 pass = pass + ti_check("spend for a priced ad = the viewable-basis figure (105)" as *u8, ainv_spent_milli(rates, rl, slog, sl, vlog, vl, clog, cl, "ha-video" as *u8) == 105); total = total + 1
92 pass = pass + ti_check("spend for an UNPRICED ad -> UNMEASURABLE, never 0" as *u8, ainv_spent_milli(rates, rl, slog, sl, vlog, vl, clog, cl, "ha-world" as *u8) == 0 - 1); total = total + 1
93 let forged: *u8 = "ha-video\nha-video\nha-video\nha-video\nha-video\nha-video\nha-video\nha-video\nha-video\nha-video\n" as *u8
94 pass = pass + ti_check("forged viewable > served -> spend UNMEASURABLE (cannot authorise)" as *u8, ainv_spent_milli(rates, rl, vlog, vl, forged, ti_slen(forged), clog, cl, "ha-video" as *u8) == 0 - 1); total = total + 1
95 pass = pass + ti_check("malformed ad id -> spend UNMEASURABLE" as *u8, ainv_spent_milli(rates, rl, slog, sl, vlog, vl, clog, cl, "bad id!" as *u8) == 0 - 1); total = total + 1
96
97 // ---- PER-ADVERTISER SCOPING: an advertiser must never see another's spend ----
98 let camps2: *u8 = "camp-a acme /synth/v.png 1000 2000 -1 live 0
99camp-b rival /synth/w.png 1000 2000 -1 live 0
100" as *u8
101 let rates2: *u8 = "camp-a 5000 100 -1
102camp-b 7000 100 -1
103" as *u8
104 let slog2: *u8 = "camp-a
105camp-a
106camp-b
107" as *u8
108 let vlog2: *u8 = "camp-a
109camp-b
110" as *u8
111 let clog2: *u8 = "" as *u8
112 let c2: i64 = ti_slen(camps2)
113 let r2: i64 = ti_slen(rates2)
114 let n7: i64 = ainv_report_for_advertiser(camps2, c2, "acme" as *u8, rates2, r2, slog2, ti_slen(slog2), vlog2, ti_slen(vlog2), clog2, 0, buf, 8192)
115 pass = pass + ti_check("advertiser report emitted" as *u8, n7 > 0); total = total + 1
116 pass = pass + ti_check("includes OWN campaign" as *u8, ti_has(buf, n7, "id=camp-a" as *u8)); total = total + 1
117 pass = pass + ti_check("EXCLUDES a rival campaign (whitelist, not redaction)" as *u8, ti_has(buf, n7, "id=camp-b" as *u8) == 0); total = total + 1
118 pass = pass + ti_check("shows served and viewable side by side (the public promise)" as *u8, ti_has(buf, n7, "served=2" as *u8)); total = total + 1
119 pass = pass + ti_check("unknown advertiser -> empty report, not everyone's" as *u8, ainv_report_for_advertiser(camps2, c2, "nobody" as *u8, rates2, r2, slog2, ti_slen(slog2), vlog2, ti_slen(vlog2), clog2, 0, buf, 8192) == 0); total = total + 1
120 pass = pass + ti_check("malformed advertiser id -> empty, never a full dump" as *u8, ainv_report_for_advertiser(camps2, c2, "bad id!" as *u8, rates2, r2, slog2, ti_slen(slog2), vlog2, ti_slen(vlog2), clog2, 0, buf, 8192) == 0); total = total + 1
121
122 ti_puts("pass=" as *u8); ti_pn(pass); ti_puts(" fail=" as *u8); ti_pn(total - pass); ti_puts("\n" as *u8)
123 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
124 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
125 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
126 let ctr__dry: *i64 = gv_ctr()
127 ctr__dry[0] = pass
128 ctr__dry[1] = total
129 let rc__dry: i64 = gv_verdict("ADNET-INVOICE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
130 sys_exit(rc__dry)
131 return rc__dry
132}