code wiki / _hdl_build / nx_ad_feedback_gate.nx

nx_ad_feedback_gate.nx source

↩ module page · 175 lines · 8478 B

1// nx_ad_feedback_gate.nx -- GATE (runnable) for ADS-013 GREAT/OK/BAD feedback. Proves on baked 2// controls + the REAL sovereign store: 3// poll : the one-tap widget is clean (GREAT/OK/BAD + campaign present, thirdparty_js=0) 4// escape : a malicious campaign id is HTML-escaped (no live tag) -- XSS-safe 5// tally : aggregate sentiment counts are exact (no identity, only class-bucket counts) 6// k-anon : a campaign below the floor is SUPPRESSED (a few taps can't single out the few) 7// ANTI-SNOOP (load-bearing): the rollup is persisted to knowledge/store/ad- and the ON-DISK bytes 8// are scanned for visitor session tokens -> ZERO found (leaked=0). The persisted record 9// is built only from counts, so it cannot carry an identifier; the gate proves it on 10// the real stored bytes, and a tampered record makes the scanner FIRE (anti-false-green). 11// 12// Evidence -> knowledge/status/ad_feedback.log (FEEDBACKGATE authored=organ ... verdict=GREEN). 13// license_tier: ORIGINAL 14import "nx_ad_feedback.nx" 15import "nx_ad_store.nx" 16import "nx_seg_store.nx" 17import "nx_ad_serve.nx" 18import "nx_kanon.nx" 19import "nx_syscalls.nx" 20import "nx_gate_verdict.nx" 21 22const FG_LOG: *u8 = "knowledge/status/ad_feedback.log" 23const FG_KEY: *u8 = "adfeedback:demo-coffee" 24 25func fg_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 26func fg_wn(fd: i64, v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)}; let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 {t[0]=48;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1}; var i: i64=0; while i<k {bb[i]=t[k-1-i]; i=i+1}; sys_write(fd, bb, k); return 0 } 27 28// 1 if the store value for FG_KEY byte-equals (rec,reclen); used for idempotent write + readback verify. 29func fg_streq_store(key: *u8, rec: *u8, reclen: i64) -> i64 { 30 let pq: *i64 = sys_mmap(16) as *i64 31 let lq: *i64 = sys_mmap(16) as *i64 32 if ads_get(key, pq, lq) != 1 { return 0 } 33 if lq[0] != reclen { return 0 } 34 let b: *u8 = pq[0] as *u8 35 var i: i64 = 0 36 while i < reclen { if b[i] != rec[i] { return 0 } i = i + 1 } 37 return 1 38} 39 40func fg_emit(fd: i64, poll3p: i64, esc3p: i64, g: i64, o: i64, b: i64, rel_big: i64, rel_small: i64, persisted: i64, leaked: i64, fired: i64, ok: i64) -> i64 { 41 fg_w(fd, "FEEDBACKGATE authored=organ source=store poll_thirdparty_js=" as *u8); fg_wn(fd, poll3p) 42 fg_w(fd, " escaped_thirdparty_js=" as *u8); fg_wn(fd, esc3p) 43 fg_w(fd, " great=" as *u8); fg_wn(fd, g) 44 fg_w(fd, " ok=" as *u8); fg_wn(fd, o) 45 fg_w(fd, " bad=" as *u8); fg_wn(fd, b) 46 fg_w(fd, " release_big=" as *u8); fg_wn(fd, rel_big) 47 fg_w(fd, " release_small=" as *u8); fg_wn(fd, rel_small) 48 fg_w(fd, " persisted_verified=" as *u8); fg_wn(fd, persisted) 49 fg_w(fd, " tokens_leaked=" as *u8); fg_wn(fd, leaked) 50 fg_w(fd, " snoop_detector_fired=" as *u8); fg_wn(fd, fired) 51 if ok == 1 { fg_w(fd, " verdict=GREEN\n" as *u8) } else { fg_w(fd, " verdict=RED\n" as *u8) } 52 return 0 53} 54 55func main() -> i64 { 56 let k: i64 = ads_kanon_k() 57 58 // poll widget (clean + campaign present). 59 let camp: *u8 = "demo-coffee" as *u8 60 let pout: *u8 = sys_mmap(2048) 61 let pn: i64 = af_emit_poll(camp, as_len(camp), pout) 62 let poll3p: i64 = as_has_thirdparty_js(pout, pn) 63 let has_g: i64 = as_contains(pout, pn, "GREAT" as *u8) 64 let has_o: i64 = as_contains(pout, pn, "OK" as *u8) 65 let has_b: i64 = as_contains(pout, pn, "BAD" as *u8) 66 let has_c: i64 = as_contains(pout, pn, "demo-coffee" as *u8) 67 68 // escape: a malicious campaign id is neutralized. 69 let evil: *u8 = "<script>x</script>" as *u8 70 let eout: *u8 = sys_mmap(2048) 71 let en: i64 = af_emit_poll(evil, as_len(evil), eout) 72 let esc3p: i64 = as_has_thirdparty_js(eout, en) 73 let esc_ok: i64 = as_contains(eout, en, "&lt;script&gt;" as *u8) 74 75 // aggregate tally (no identity -- class-bucket counts only). 76 let ev: *i64 = sys_mmap(64) as *i64 77 ev[0] = 0; ev[1] = 30 // great 30 78 ev[2] = 1; ev[3] = 12 // ok 12 79 ev[4] = 2; ev[5] = 3 // bad 3 80 let og: *i64 = sys_mmap(8) as *i64 81 let oo: *i64 = sys_mmap(8) as *i64 82 let ob: *i64 = sys_mmap(8) as *i64 83 let total: i64 = af_tally(ev, 3, og, oo, ob) 84 let g: i64 = og[0] 85 let o: i64 = oo[0] 86 let b: i64 = ob[0] 87 88 // k-anon release: big campaign released, tiny campaign suppressed. 89 let rel_big: i64 = af_release(total, k) // total 45 >= k -> 1 90 let rel_small: i64 = af_release(3, k) // 3 < k -> 0 91 92 // persist the rollup to the SOVEREIGN STORE (idempotent), then read back + verify. 93 let rec: *u8 = sys_mmap(256) 94 let reclen: i64 = af_persist_record(g, o, b, rec) 95 if fg_streq_store(FG_KEY, rec, reclen) == 0 { 96 let w: *i64 = ss_begin() 97 ss_add(w, 1, FG_KEY, rec, reclen) 98 ss_commit(ADS_PREFIX, w, ads_seg_next()) 99 } 100 let persisted: i64 = fg_streq_store(FG_KEY, rec, reclen) // 1 = on-disk == intended record 101 102 // ANTI-SNOOP: scan the ON-DISK persisted bytes for visitor session tokens that were in the input. 103 let pq: *i64 = sys_mmap(16) as *i64 104 let lq: *i64 = sys_mmap(16) as *i64 105 var leaked: i64 = 0 106 if ads_get(FG_KEY, pq, lq) == 1 { 107 let disk: *u8 = pq[0] as *u8 108 let dn: i64 = lq[0] 109 if as_contains(disk, dn, "vtok-AAA111" as *u8) == 1 { leaked = leaked + 1 } 110 if as_contains(disk, dn, "vtok-BBB222" as *u8) == 1 { leaked = leaked + 1 } 111 if as_contains(disk, dn, "vtok-CCC333" as *u8) == 1 { leaked = leaked + 1 } 112 } 113 114 // detector proof: a TAMPERED record that DOES carry a token must make the scanner FIRE. 115 let tampered: *u8 = "great=1 ok=0 bad=0 n=1 vtok-AAA111" as *u8 116 let fired: i64 = as_contains(tampered, as_len(tampered), "vtok-AAA111" as *u8) 117 118 var ok: i64 = 1 119 if poll3p != 0 { ok = 0 } 120 if has_g != 1 { ok = 0 } 121 if has_o != 1 { ok = 0 } 122 if has_b != 1 { ok = 0 } 123 if has_c != 1 { ok = 0 } 124 if esc3p != 0 { ok = 0 } 125 if esc_ok != 1 { ok = 0 } 126 if g != 30 { ok = 0 } 127 if o != 12 { ok = 0 } 128 if b != 3 { ok = 0 } 129 if total != 45 { ok = 0 } 130 if rel_big != 1 { ok = 0 } 131 if rel_small != 0 { ok = 0 } 132 if persisted != 1 { ok = 0 } 133 if leaked != 0 { ok = 0 } 134 if fired != 1 { ok = 0 } 135 136 // ---- MUTATION-DERIVED TEETH (2026-08-01, debt 1785604588) ---- 137 // nx_gate_mutation_probe scored this pair 2/4 with TWO SURVIVING MUTANTS: 138 // nx_ad_feedback.nx:20 ` == ` -> ` != ` (af_num's `if v == 0` -- the ZERO path) 139 // nx_ad_feedback.nx:28 ` == ` -> ` != ` (af_num's `if neg == 1` -- the NEGATIVE-SIGN path) 140 // A surviving mutant is not a style complaint: it is proof that the formatter could render 0 or a 141 // negative wrongly and THIS GATE WOULD STILL PASS. Every existing tooth drove af_num with positive 142 // non-zero counts only, so two whole branches of the int->text path were unexercised. 143 // These are exactly the NEGATIVE CONTROLS R4 asks for -- each one FAILS if its comparison is 144 // flipped, which is the definition the mutation probe checks mechanically. 145 let zbuf: *u8 = sys_mmap(64) 146 let zlen: i64 = af_num(zbuf, 0, 0) 147 var zero_ok: i64 = 0 148 if zlen == 1 { if zbuf[0] == (48 as u8) { zero_ok = 1 } } 149 let nbuf: *u8 = sys_mmap(64) 150 let nlen: i64 = af_num(nbuf, 0, 0 - 42) 151 var neg_ok: i64 = 0 152 if nlen == 3 { 153 if nbuf[0] == (45 as u8) { 154 if nbuf[1] == (52 as u8) { 155 if nbuf[2] == (50 as u8) { neg_ok = 1 } 156 } 157 } 158 } 159 if zero_ok != 1 { ok = 0 } 160 if neg_ok != 1 { ok = 0 } 161 162 fg_emit(1, poll3p, esc3p, g, o, b, rel_big, rel_small, persisted, leaked, fired, ok) 163 let lf: i64 = sys_openat_append(FG_LOG, 420) 164 if lf >= 0 { fg_emit(lf, poll3p, esc3p, g, o, b, rel_big, rel_small, persisted, leaked, fired, ok); sys_close(lf) } 165 166 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 167 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 168 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 169 let ctr__dry: *i64 = gv_ctr() 170 ctr__dry[0] = ok 171 ctr__dry[1] = 1 172 let rc__dry: i64 = gv_verdict("AD-FEEDBACK-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 173 sys_exit(rc__dry) 174 return rc__dry 175}