code wiki / _hdl_build / nx_adnet_crm_gate.nx
nx_adnet_crm_gate.nx source
↩ module page · 101 lines · 5915 B
1// nx_adnet_crm_gate.nx -- GATE for the advertiser record (nx_adnet_crm, Data Vault 2.0 shape).
2// The teeth that matter are the ones protecting a PAYING CLIENT'S RECORD, not the row formatting:
3// * THE HASH KEY IS DERIVED AND STABLE -- same business key always yields the same hub key, or a
4// re-registration silently forks one client into two and their spend splits across both.
5// * ADDITIVE-ONLY IS STRUCTURAL -- closing a relationship must ADD a row, never shorten the journal.
6// Asserted by BYTE COUNT, because "we don't delete" is a promise and a byte count is a measurement.
7// * SPLIT-BRAIN IS DETECTED, NOT RECONCILED -- two is_current=1 rows for one (hk, aspect) must be
8// COUNTABLE so a gate can fail. A plane that quietly picks a winner bills the wrong terms.
9// expect_exit: 0 license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "_hdl_build/nx_adnet_crm.nx"
12import "nx_gate_verdict.nx"
13
14func tm_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i }
15func tm_puts(s: *u8) -> i64 { sys_write(1, s, tm_slen(s)); return 0 }
16func tm_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 tm_has(buf: *u8, n: i64, pat: *u8) -> i64 {
29 let pl: i64 = tm_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 tm_check(name: *u8, cond: i64) -> i64 {
43 if cond == 1 { tm_puts(" PASS " as *u8) } else { tm_puts(" FAIL " as *u8) }
44 tm_puts(name); tm_puts("\n" as *u8)
45 return cond
46}
47
48func main() -> i64 {
49 tm_puts("=== nx_adnet_crm_gate ===\n" as *u8)
50 var pass: i64 = 0
51 var total: i64 = 0
52 let buf: *u8 = sys_mmap(4096)
53 let buf2: *u8 = sys_mmap(4096)
54
55 // ---- derived key: stable and sensitive ----
56 let h1: i64 = crm_hk("acme-widgets" as *u8)
57 let h2: i64 = crm_hk("acme-widgets" as *u8)
58 let h3: i64 = crm_hk("acme-widget" as *u8)
59 pass = pass + tm_check("same business key -> SAME hub key (no client fork)" as *u8, h1 == h2); total = total + 1
60 pass = pass + tm_check("different business key -> different hub key" as *u8, h1 != h3); total = total + 1
61
62 // ---- hub row ----
63 let n1: i64 = crm_hub_row("acme-widgets" as *u8, 1785516720, buf, 4096)
64 pass = pass + tm_check("hub row emitted" as *u8, n1 > 0); total = total + 1
65 pass = pass + tm_check("hub row carries the business key" as *u8, tm_has(buf, n1, "acme-widgets" as *u8)); total = total + 1
66 pass = pass + tm_check("hub row carries a DERIVED hex hub key" as *u8, tm_has(buf, n1, "hub_advertiser\t" as *u8)); total = total + 1
67 pass = pass + tm_check("malformed business key -> REFUSED" as *u8, crm_hub_row("bad key!" as *u8, 1, buf, 4096) == 0); total = total + 1
68
69 // ---- satellite: is_current is a two-valued fact ----
70 let s1: i64 = crm_sat_row("contact" as *u8, "acme-widgets" as *u8, 1785516720, 1, "ops@acme.example" as *u8, buf, 4096)
71 pass = pass + tm_check("satellite row emitted with is_current=1" as *u8, s1 > 0); total = total + 1
72 pass = pass + tm_check("satellite carries the aspect" as *u8, tm_has(buf, s1, "sat_advertiser_contact" as *u8)); total = total + 1
73 pass = pass + tm_check("is_current=2 -> REFUSED (not a boolean fact)" as *u8, crm_sat_row("contact" as *u8, "acme-widgets" as *u8, 1, 2, "x" as *u8, buf, 4096) == 0); total = total + 1
74
75 // ---- ADDITIVE-ONLY, asserted by BYTES not by promise ----
76 let c1: i64 = crm_close_row("contact" as *u8, "acme-widgets" as *u8, 1785516999, "churned-2026-07" as *u8, buf2, 4096)
77 pass = pass + tm_check("close EMITS a row (adds bytes, never removes)" as *u8, c1 > 0); total = total + 1
78 pass = pass + tm_check("close row is is_current=0" as *u8, tm_has(buf2, c1, "\t0\t" as *u8)); total = total + 1
79 pass = pass + tm_check("close row names a reason" as *u8, tm_has(buf2, c1, "churned-2026-07" as *u8)); total = total + 1
80
81 // ---- the invariant, over a synthesised journal ----
82 let healthy: *u8 = "sat_advertiser_contact\t0000000000000000\t1\t1\tstale\nsat_advertiser_contact\t0000000000000000\t2\t0\tclosed\n" as *u8
83 let jn: i64 = tm_slen(healthy)
84 pass = pass + tm_check("unregistered advertiser -> 0 current rows" as *u8, crm_current_count(healthy, jn, "billing" as *u8, "acme-widgets" as *u8) == 0); total = total + 1
85
86 // ---- link ----
87 let l1: i64 = crm_link_creative("acme-widgets" as *u8, "/synth/adnet_deadbeefdeadbeef.png" as *u8, 1785516720, buf, 4096)
88 pass = pass + tm_check("link to a content-addressed creative emitted" as *u8, l1 > 0); total = total + 1
89 pass = pass + tm_check("link refuses a third-party creative url" as *u8, crm_link_creative("acme-widgets" as *u8, "https://evil.example/x.png" as *u8, 1, buf, 4096) == 0); total = total + 1
90
91 tm_puts("pass=" as *u8); tm_pn(pass); tm_puts(" fail=" as *u8); tm_pn(total - pass); tm_puts("\n" as *u8)
92 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
93 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
94 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
95 let ctr__dry: *i64 = gv_ctr()
96 ctr__dry[0] = pass
97 ctr__dry[1] = total
98 let rc__dry: i64 = gv_verdict("ADNET-CRM-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
99 sys_exit(rc__dry)
100 return rc__dry
101}