code wiki / (root) / nx_vizsla_notify_mcp_gate.nx

nx_vizsla_notify_mcp_gate.nx source

↩ module page · 158 lines · 6372 B

1// nx_vizsla_notify_mcp_gate.nx -- GATE: the COMPOSING vizsla_notify tool runs over the tools/call 2// execution layer. Kept SEPARATE from nx_vizsla_mcp_gate (a fresh, minimal process) because notify is 3// a COMPOSING tool -- it forks the blessed remind engine -- so this proves the double-fork path 4// (grandparent tools/call -> notify -> remind) works over tea_run_argv, exactly as the live /mcp does. 5// 6// Rows: 1 notify-resolve 2 mcp-exec-email (RFC5322 + Date header) 3 mcp-exec-deliver (on-site) 7// Evidence: VIZSLA-NOTIFY-MCP-GATE -> stdout + knowledge/status/vizsla_gate.log; exit 0 iff 3/3. 8// expect_exit: 0 license_tier: ORIGINAL 9import "nx_tool_exec_allow.nx" 10import "nx_gate_verdict.nx" 11 12func mn_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 13func mn_p(s: *u8) -> i64 { sys_write(1, s, mn_slen(s)); return 0 } 14 15func mn_cat(dst: *u8, off: i64, s: *u8) -> i64 { 16 var i: i64 = 0 17 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 18 return off + i 19} 20 21func mn_catn(dst: *u8, off: i64, v: i64) -> i64 { 22 var o: i64 = off 23 var m: i64 = v 24 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m } 25 let t: *u8 = sys_mmap(28) 26 var k: i64 = 0 27 if m == 0 { t[0] = 48 as u8; k = 1 } 28 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 29 var i: i64 = 0 30 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 } 31 return o + k 32} 33 34func mn_memhas(b: *u8, sz: i64, needle: *u8) -> i64 { 35 let n: i64 = mn_slen(needle) 36 if sz < n { return 0 } 37 var i: i64 = 0 38 while i + n <= sz { 39 var ok: i64 = 1 40 var j: i64 = 0 41 while j < n { if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 } } 42 if ok == 1 { return 1 } 43 i = i + 1 44 } 45 return 0 46} 47 48func mn_filehas(path: *u8, needle: *u8) -> i64 { 49 let fd: i64 = sys_openat_rd(path) 50 if fd < 0 { return 0 } 51 let sz: i64 = sys_lseek(fd, 0, 2) 52 sys_lseek(fd, 0, 0) 53 let buf: *u8 = sys_mmap(sz + 64) 54 var got: i64 = 0 55 var n: i64 = 1 56 while n > 0 { n = sys_read(fd, (buf as i64 + got) as *u8, 65536); if n > 0 { got = got + n } } 57 sys_close(fd) 58 return mn_memhas(buf, got, needle) 59} 60 61func mn_row(name: *u8, pass: i64) -> i64 { 62 mn_p("ROW " as *u8) 63 mn_p(name) 64 if pass == 1 { mn_p(" PASS\n" as *u8) } else { mn_p(" FAIL\n" as *u8) } 65 return pass 66} 67 68func main(argc: i64, argv: *i64) -> i64 { 69 mn_p("=== VIZSLA NOTIFY MCP GATE: the composing notify tool runs over tools/call (double-fork) ===\n" as *u8) 70 let conf: *u8 = "tool_allowlist.conf" as *u8 71 let out: *u8 = sys_mmap(16384) 72 let outlen: *i64 = sys_mmap(16) as *i64 73 let rc: *i64 = sys_mmap(16) as *i64 74 var pass: i64 = 0 75 var r: i64 = 0 76 77 // row 1: resolve 78 let path: *u8 = sys_mmap(4096) 79 let code: i64 = tea_resolve_from(conf, "vizsla_notify" as *u8, 13, path, 4096) 80 r = 0 81 if code == TEA_OK { if mn_memhas(path, mn_slen(path), "_offc/nx_vizsla_notify.elf" as *u8) == 1 { r = 1 } } 82 pass = pass + mn_row("notify-resolve" as *u8, r) 83 84 // row 2: EXECUTE email over tools/call (FIRST fork -> notify forks remind = the double-fork path) 85 let av: *i64 = sys_mmap(8 * 12) as *i64 86 av[0] = 0 87 av[1] = "email" as *u8 as i64 88 av[2] = "knowledge/vizsla/demo/cal-" as *u8 as i64 89 av[3] = "knowledge/vizsla/demo/contacts.txt" as *u8 as i64 90 av[4] = "2026-07-08" as *u8 as i64 91 av[5] = "14,7,1,0" as *u8 as i64 92 av[6] = "vizsla@jasonewest.com" as *u8 as i64 93 av[7] = "you@example.com" as *u8 as i64 94 av[8] = "/tmp/vzmn_email.eml" as *u8 as i64 95 av[9] = 0 96 let x2: i64 = tea_run_argv_from(conf, "vizsla_notify" as *u8, 13, av, out, 16384, outlen, rc) 97 r = 0 98 if x2 == 0 { if rc[0] == TEA_OK { 99 if mn_memhas(out, outlen[0], "VIZSLA-NOTIFY-EMAIL today=2026-07-08" as *u8) == 1 { 100 if mn_filehas("/tmp/vzmn_email.eml" as *u8, "Date: Wed, 08 Jul 2026 09:00:00 +0000" as *u8) == 1 { r = 1 } 101 } 102 } } 103 pass = pass + mn_row("mcp-exec-email" as *u8, r) 104 105 // row 3: EXECUTE on-site deliver over tools/call 106 let pfx: *u8 = sys_mmap(128) 107 var po: i64 = 0 108 po = mn_cat(pfx, po, "/tmp/vzmnN" as *u8) 109 po = mn_catn(pfx, po, sys_now_us()) 110 po = mn_cat(pfx, po, "-" as *u8) 111 pfx[po] = 0 as u8 112 let av3: *i64 = sys_mmap(8 * 12) as *i64 113 av3[0] = 0 114 av3[1] = "deliver" as *u8 as i64 115 av3[2] = pfx as i64 116 av3[3] = "knowledge/vizsla/demo/cal-" as *u8 as i64 117 av3[4] = "knowledge/vizsla/demo/contacts.txt" as *u8 as i64 118 av3[5] = "2026-07-08" as *u8 as i64 119 av3[6] = "0" as *u8 as i64 120 av3[7] = 0 121 let x3: i64 = tea_run_argv_from(conf, "vizsla_notify" as *u8, 13, av3, out, 16384, outlen, rc) 122 r = 0 123 if x3 == 0 { if rc[0] == TEA_OK { 124 if mn_memhas(out, outlen[0], "VIZSLA-NOTIFY-DELIVER channel=onsite today=2026-07-08" as *u8) == 1 { r = 1 } 125 } } 126 pass = pass + mn_row("mcp-exec-deliver" as *u8, r) 127 128 let permil: i64 = (pass * 1000) / 3 129 let logfd: i64 = sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4) 130 var fdi: i64 = 0 131 while fdi < 2 { 132 var fd: i64 = 1 133 if fdi == 1 { fd = logfd } 134 if fd > 0 { 135 let line: *u8 = sys_mmap(256) 136 var o: i64 = 0 137 o = mn_cat(line, o, "VIZSLA-NOTIFY-MCP-GATE epoch=" as *u8) 138 o = mn_catn(line, o, sys_now_realtime_sec()) 139 o = mn_cat(line, o, " rows=3 pass=" as *u8) 140 o = mn_catn(line, o, pass) 141 o = mn_cat(line, o, " permil=" as *u8) 142 o = mn_catn(line, o, permil) 143 if pass == 3 { o = mn_cat(line, o, " verdict=GREEN\n" as *u8) } else { o = mn_cat(line, o, " verdict=RED\n" as *u8) } 144 sys_write(fd, line, o) 145 } 146 fdi = fdi + 1 147 } 148 if logfd > 0 { sys_close(logfd) } 149 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 150 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 151 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 152 let ctr__dry: *i64 = gv_ctr() 153 ctr__dry[0] = pass 154 ctr__dry[1] = 3 155 let rc__dry: i64 = gv_verdict("VIZSLA-NOTIFY-MCP-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 156 sys_exit(rc__dry) 157 return rc__dry 158}