code wiki / _hdl_build / nx_vizsla_notify_gate.nx

nx_vizsla_notify_gate.nx source

↩ module page · 318 lines · 13647 B

1// nx_vizsla_notify_gate.nx -- VIZSLA OUTWARD-DELIVERY gate: reminders REACH you. COMPOSITION: the 2// calendar store is loaded through the blessed calendar organ; notify forks the blessed remind engine 3// for the due computation; the notification store is the once-only delivery ledger. 4// 5// fixture: calendar mtg 2026-07-08 10:00, gala 2026-08-20 18:00; contacts mom 07-14, dad 07-08. 6// deliver today=2026-07-08 leads=6,0 -> mtg(event in0) + dad(bday in0) + mom(bday in6) = 3 delivered 7// re-deliver same -> 0 delivered / 3 skipped (own store is the ledger) 8// deliver today=2026-08-14 leads=6,0 -> gala(event in6, NEW occurrence) = 1 delivered 9// feed -> 4 notifications; feed birthday -> 2 (mom, dad) 10// email today=2026-07-08 -> RFC5322 digest, 3 reminders, Date: Wed, 08 Jul 2026 09:00:00 +0000 11// 12// Rows: 1 fixture-loads 2 deliver-onsite 3 feed-lists 4 deliver-idempotent 5 deliver-new-occurrence 13// 6 feed-after 7 feed-kind-filter 8 email-compose 9 email-date-header 10 email-body-bullet 14// 11 feed-determinism 12 loud-fail-bad-today[neg] 13 loud-fail-bad-leads[neg] 15// Evidence: VIZSLA-NOTIFY-GATE -> stdout + knowledge/status/vizsla_gate.log; exit 0 iff 13/13. 16// spec: knowledge/research/2026-06-22-vizsla-sclass-roadmap.md license_tier: ORIGINAL 17import "nx_syscalls.nx" 18import "nx_gate_verdict.nx" 19 20func ng_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 21func ng_p(s: *u8) -> i64 { sys_write(1, s, ng_slen(s)); return 0 } 22 23func ng_cat(dst: *u8, off: i64, s: *u8) -> i64 { 24 var i: i64 = 0 25 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 26 return off + i 27} 28 29func ng_catn(dst: *u8, off: i64, v: i64) -> i64 { 30 var o: i64 = off 31 var m: i64 = v 32 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m } 33 let t: *u8 = sys_mmap(28) 34 var k: i64 = 0 35 if m == 0 { t[0] = 48 as u8; k = 1 } 36 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 37 var i: i64 = 0 38 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 } 39 return o + k 40} 41 42func ng_write(path: *u8, content: *u8) -> i64 { 43 let fd: i64 = sys_openat_wr(path, 0x1a4) 44 if fd < 0 { return 0 - 1 } 45 sys_write(fd, content, ng_slen(content)) 46 sys_close(fd) 47 return 0 48} 49 50func ng_readall(path: *u8, szout: *i64) -> *u8 { 51 let fd: i64 = sys_openat_rd(path) 52 if fd < 0 { szout[0] = 0 - 1; return 0 as *u8 } 53 let sz: i64 = sys_lseek(fd, 0, 2) 54 sys_lseek(fd, 0, 0) 55 let buf: *u8 = sys_mmap(sz + 64) 56 var got: i64 = 0 57 var n: i64 = 1 58 while n > 0 { 59 n = sys_read(fd, (buf as i64 + got) as *u8, 65536) 60 if n > 0 { got = got + n } 61 } 62 sys_close(fd) 63 szout[0] = got 64 return buf 65} 66 67func ng_runv(elf: *u8, args: *i64, outpath: *u8) -> i64 { 68 let pid: i64 = sys_fork() 69 if pid == 0 { 70 if (outpath as i64) != 0 { 71 let ofd: i64 = sys_openat_wr(outpath, 0x1a4) 72 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } 73 } 74 let argv: *i64 = sys_mmap(128) as *i64 75 argv[0] = elf as i64 76 var i: i64 = 0 77 var go: i64 = 1 78 while go == 1 { 79 if args[i] == 0 { go = 0 } else { 80 argv[i + 1] = args[i] 81 i = i + 1 82 } 83 } 84 argv[i + 1] = 0 85 let envp: *i64 = sys_mmap(16) as *i64 86 envp[0] = 0 87 sys_execve(elf, argv, envp) 88 sys_exit(127) 89 } 90 let st: *i64 = sys_mmap(16) as *i64 91 sys_wait4(pid, st, 0) 92 let sig: i64 = st[0] & 0x7f 93 if sig != 0 { return 128 + sig } 94 return (st[0] >> 8) & 0xff 95} 96 97func ng_has(path: *u8, needle: *u8) -> i64 { 98 let szp: *i64 = sys_mmap(16) as *i64 99 let b: *u8 = ng_readall(path, szp) 100 let sz: i64 = szp[0] 101 let n: i64 = ng_slen(needle) 102 if sz < n { return 0 } 103 var i: i64 = 0 104 while i + n <= sz { 105 var ok: i64 = 1 106 var j: i64 = 0 107 while j < n { 108 if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 } 109 } 110 if ok == 1 { return 1 } 111 i = i + 1 112 } 113 return 0 114} 115 116func ng_fileeq(p1: *u8, p2: *u8) -> i64 { 117 let s1: *i64 = sys_mmap(16) as *i64 118 let s2: *i64 = sys_mmap(16) as *i64 119 let b1: *u8 = ng_readall(p1, s1) 120 let b2: *u8 = ng_readall(p2, s2) 121 if s1[0] != s2[0] { return 0 } 122 if s1[0] <= 0 { return 0 } 123 var i: i64 = 0 124 while i < s1[0] { 125 if b1[i] != b2[i] { return 0 } 126 i = i + 1 127 } 128 return 1 129} 130 131func ng_row(name: *u8, pass: i64) -> i64 { 132 ng_p("ROW " as *u8) 133 ng_p(name) 134 if pass == 1 { ng_p(" PASS\n" as *u8) } else { ng_p(" FAIL\n" as *u8) } 135 return pass 136} 137 138func ng_args(a1: *u8, a2: *u8, a3: *u8, a4: *u8, a5: *u8, a6: *u8, a7: *u8, a8: *u8) -> *i64 { 139 let a: *i64 = sys_mmap(128) as *i64 140 a[0] = a1 as i64 141 a[1] = a2 as i64 142 a[2] = a3 as i64 143 a[3] = a4 as i64 144 a[4] = a5 as i64 145 a[5] = a6 as i64 146 a[6] = a7 as i64 147 a[7] = a8 as i64 148 a[8] = 0 149 return a 150} 151 152func ng_ensure(elf: *u8, organ: *u8) -> i64 { 153 let pr: i64 = sys_openat_rd(elf) 154 if pr >= 0 { sys_close(pr); return 0 } 155 ng_p(" instrument missing -> rebuilding via durable runner\n" as *u8) 156 ng_runv("_offc/nx_sov_build_run.elf" as *u8, ng_args(organ, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_rebuild.out" as *u8) 157 return 0 158} 159 160func main(argc: i64, argv: *i64) -> i64 { 161 ng_p("=== VIZSLA NOTIFY GATE: outward delivery (on-site once-only + RFC5322 email compose) ===\n" as *u8) 162 let ntf: *u8 = "buildroot/_build/nx_vizsla_notify.sov.elf" as *u8 163 let cal: *u8 = "buildroot/_build/nx_vizsla_calendar.sov.elf" as *u8 164 ng_ensure(ntf, "nx_vizsla_notify" as *u8) 165 ng_ensure(cal, "nx_vizsla_calendar" as *u8) 166 // notify forks the BLESSED _offc/nx_vizsla_remind.elf -- ensure it exists 167 let rp: i64 = sys_openat_rd("_offc/nx_vizsla_remind.elf" as *u8) 168 if rp >= 0 { sys_close(rp) } else { 169 ng_runv("_offc/nx_sov_build_run.elf" as *u8, ng_args("nx_vizsla_remind" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_rem.out" as *u8) 170 } 171 172 let us: i64 = sys_now_us() 173 let cpfx: *u8 = sys_mmap(128) 174 var po: i64 = 0 175 po = ng_cat(cpfx, po, "/tmp/vznC" as *u8) 176 po = ng_catn(cpfx, po, us) 177 po = ng_cat(cpfx, po, "-" as *u8) 178 cpfx[po] = 0 as u8 179 let npfx: *u8 = sys_mmap(128) 180 po = 0 181 po = ng_cat(npfx, po, "/tmp/vznN" as *u8) 182 po = ng_catn(npfx, po, us) 183 po = ng_cat(npfx, po, "-" as *u8) 184 npfx[po] = 0 as u8 185 186 ng_write("/tmp/vzn_cal.txt" as *u8, "EVENT mtg 2026-07-08 600 60 standup-mtg\nEVENT gala 2026-08-20 1080 120 summer-gala\n" as *u8) 187 ng_write("/tmp/vzn_ct.txt" as *u8, "TIER inner 7\nCONTACT mom Mom inner 07-14\nCONTACT dad Dad inner 07-08\n" as *u8) 188 189 var pass: i64 = 0 190 var r: i64 = 0 191 192 // row 1: calendar loads 193 let rc1: i64 = ng_runv(cal, ng_args("load" as *u8, "/tmp/vzn_cal.txt" as *u8, cpfx, "7501" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_l1.txt" as *u8) 194 r = 0 195 if rc1 == 0 { if ng_has("/tmp/vzn_l1.txt" as *u8, "VIZSLA-CAL-LOAD scanned=2 new=2" as *u8) == 1 { r = 1 } } 196 pass = pass + ng_row("fixture-loads" as *u8, r) 197 198 // row 2: deliver on-site 199 let rc2: i64 = ng_runv(ntf, ng_args("deliver" as *u8, npfx, cpfx, "/tmp/vzn_ct.txt" as *u8, "2026-07-08" as *u8, "6,0" as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r2.txt" as *u8) 200 r = 0 201 if rc2 == 0 { if ng_has("/tmp/vzn_r2.txt" as *u8, "VIZSLA-NOTIFY-DELIVER channel=onsite today=2026-07-08 delivered=3 skipped=0" as *u8) == 1 { r = 1 } } 202 pass = pass + ng_row("deliver-onsite" as *u8, r) 203 204 // row 3: feed lists the delivered notices 205 let rc3: i64 = ng_runv(ntf, ng_args("feed" as *u8, npfx, "-" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r3.txt" as *u8) 206 r = 0 207 if rc3 == 0 { 208 if ng_has("/tmp/vzn_r3.txt" as *u8, "VIZSLA-NOTIFY channel=onsite kind=birthday id=mom date=2026-07-14 on=2026-07-08 title=Mom" as *u8) == 1 { 209 if ng_has("/tmp/vzn_r3.txt" as *u8, "VIZSLA-NOTIFY-FEED kind=- notifications=3" as *u8) == 1 { r = 1 } 210 } 211 } 212 pass = pass + ng_row("feed-lists" as *u8, r) 213 214 // row 4: idempotent re-deliver 215 let rc4: i64 = ng_runv(ntf, ng_args("deliver" as *u8, npfx, cpfx, "/tmp/vzn_ct.txt" as *u8, "2026-07-08" as *u8, "6,0" as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r4.txt" as *u8) 216 r = 0 217 if rc4 == 0 { if ng_has("/tmp/vzn_r4.txt" as *u8, "delivered=0 skipped=3 segment=none" as *u8) == 1 { r = 1 } } 218 pass = pass + ng_row("deliver-idempotent" as *u8, r) 219 220 // row 5: a genuinely new occurrence delivers 221 let rc5: i64 = ng_runv(ntf, ng_args("deliver" as *u8, npfx, cpfx, "/tmp/vzn_ct.txt" as *u8, "2026-08-14" as *u8, "6,0" as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r5.txt" as *u8) 222 r = 0 223 if rc5 == 0 { if ng_has("/tmp/vzn_r5.txt" as *u8, "today=2026-08-14 delivered=1 skipped=0" as *u8) == 1 { r = 1 } } 224 pass = pass + ng_row("deliver-new-occurrence" as *u8, r) 225 226 // row 6: feed now shows 4 227 let rc6: i64 = ng_runv(ntf, ng_args("feed" as *u8, npfx, "-" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r6.txt" as *u8) 228 r = 0 229 if rc6 == 0 { if ng_has("/tmp/vzn_r6.txt" as *u8, "VIZSLA-NOTIFY-FEED kind=- notifications=4" as *u8) == 1 { r = 1 } } 230 pass = pass + ng_row("feed-after" as *u8, r) 231 232 // row 7: kind filter 233 let rc7: i64 = ng_runv(ntf, ng_args("feed" as *u8, npfx, "birthday" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r7.txt" as *u8) 234 r = 0 235 if rc7 == 0 { 236 if ng_has("/tmp/vzn_r7.txt" as *u8, "VIZSLA-NOTIFY-FEED kind=birthday notifications=2" as *u8) == 1 { 237 if ng_has("/tmp/vzn_r7.txt" as *u8, "kind=event" as *u8) == 0 { r = 1 } 238 } 239 } 240 pass = pass + ng_row("feed-kind-filter" as *u8, r) 241 242 // row 8: email compose 243 let rc8: i64 = ng_runv(ntf, ng_args("email" as *u8, cpfx, "/tmp/vzn_ct.txt" as *u8, "2026-07-08" as *u8, "6,0" as *u8, "vizsla@jasonewest.com" as *u8, "you@example.com" as *u8, "/tmp/vzn_out.eml" as *u8), "/tmp/vzn_r8.txt" as *u8) 244 r = 0 245 if rc8 == 0 { 246 if ng_has("/tmp/vzn_r8.txt" as *u8, "VIZSLA-NOTIFY-EMAIL today=2026-07-08 reminders=3" as *u8) == 1 { 247 if ng_has("/tmp/vzn_out.eml" as *u8, "From: vizsla@jasonewest.com" as *u8) == 1 { 248 if ng_has("/tmp/vzn_out.eml" as *u8, "To: you@example.com" as *u8) == 1 { 249 if ng_has("/tmp/vzn_out.eml" as *u8, "Subject: Your reminders for 2026-07-08" as *u8) == 1 { r = 1 } 250 } 251 } 252 } 253 } 254 pass = pass + ng_row("email-compose" as *u8, r) 255 256 // row 9: valid RFC5322 Date header (DOW math end-to-end: 2026-07-08 = Wednesday) 257 r = ng_has("/tmp/vzn_out.eml" as *u8, "Date: Wed, 08 Jul 2026 09:00:00 +0000" as *u8) 258 pass = pass + ng_row("email-date-header" as *u8, r) 259 260 // row 10: the digest body carries the reminders 261 r = 0 262 if ng_has("/tmp/vzn_out.eml" as *u8, "Nishi Vizsla reminders:" as *u8) == 1 { 263 if ng_has("/tmp/vzn_out.eml" as *u8, "* Mom (birthday) on 2026-07-14 -- in 6 days" as *u8) == 1 { r = 1 } 264 } 265 pass = pass + ng_row("email-body-bullet" as *u8, r) 266 267 // row 11: feed determinism 268 ng_runv(ntf, ng_args("feed" as *u8, npfx, "-" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r11.txt" as *u8) 269 r = ng_fileeq("/tmp/vzn_r6.txt" as *u8, "/tmp/vzn_r11.txt" as *u8) 270 pass = pass + ng_row("feed-determinism" as *u8, r) 271 272 // row 12: bad today (negative control) 273 let rc12: i64 = ng_runv(ntf, ng_args("deliver" as *u8, npfx, cpfx, "/tmp/vzn_ct.txt" as *u8, "2026-13-99" as *u8, "6,0" as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r12.txt" as *u8) 274 r = 0 275 if rc12 == 1 { r = 1 } 276 pass = pass + ng_row("loud-fail-bad-today" as *u8, r) 277 278 // row 13: bad leads propagate from remind (negative control) 279 let rc13: i64 = ng_runv(ntf, ng_args("deliver" as *u8, npfx, cpfx, "/tmp/vzn_ct.txt" as *u8, "2026-07-08" as *u8, "x,1" as *u8, 0 as *u8, 0 as *u8), "/tmp/vzn_r13.txt" as *u8) 280 r = 0 281 if rc13 == 1 { r = 1 } 282 pass = pass + ng_row("loud-fail-bad-leads" as *u8, r) 283 284 let permil: i64 = (pass * 1000) / 13 285 let logfd: i64 = sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4) 286 var fdi: i64 = 0 287 while fdi < 2 { 288 var fd: i64 = 1 289 if fdi == 1 { fd = logfd } 290 if fd > 0 { 291 let line: *u8 = sys_mmap(256) 292 var o: i64 = 0 293 o = ng_cat(line, o, "VIZSLA-NOTIFY-GATE epoch=" as *u8) 294 o = ng_catn(line, o, sys_now_realtime_sec()) 295 o = ng_cat(line, o, " rows=13 pass=" as *u8) 296 o = ng_catn(line, o, pass) 297 o = ng_cat(line, o, " permil=" as *u8) 298 o = ng_catn(line, o, permil) 299 if pass == 13 { 300 o = ng_cat(line, o, " verdict=GREEN\n" as *u8) 301 } else { 302 o = ng_cat(line, o, " verdict=RED\n" as *u8) 303 } 304 sys_write(fd, line, o) 305 } 306 fdi = fdi + 1 307 } 308 if logfd > 0 { sys_close(logfd) } 309 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 310 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 311 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 312 let ctr__dry: *i64 = gv_ctr() 313 ctr__dry[0] = pass 314 ctr__dry[1] = 13 315 let rc__dry: i64 = gv_verdict("VIZSLA-NOTIFY-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 316 sys_exit(rc__dry) 317 return rc__dry 318}