code wiki / _hdl_build / nx_vizsla_group_gate.nx

nx_vizsla_group_gate.nx source

↩ module page · 360 lines · 16170 B

1// nx_vizsla_group_gate.nx -- VIZSLA GROUP gate: multi-member find-a-time + slot poll proven 2// against HAND-COMPUTED intersection fixtures. GENUINE COMPOSITION: member calendars are loaded 3// through the real nx_vizsla_calendar organ (cal: + rec: records), then nx_vizsla_group reads 4// those member stores -- nothing is mocked. 5// 6// member calendars (2026-07-10): 7// alice: 09:00-10:00 planning, 13:00-14:00 lunch 8// bob: 10:00-12:00 work, RRULE gym DAILY x2 15:00-16:00 (07-10 + 07-11) 9// group busy union 07-10: [540,720) [780,840) [900,960) 10// free in [480,1320): [480,540) [720,780) [840,900) [960,1320) 11// findtime dur=60 07-10 -> 4 candidates (08:00,12:00,14:00,16:00 windows) 12// findtime dur=90 07-10..07-11 -> 3 (evening 07-10 + two 07-11 windows; short gaps drop) 13// 07-11 dur=60 -> free ends 15:00 where bob's RECURRING gym starts 14// poll p1: s1 2026-07-10 16:00+90, s2 2026-07-11 08:00+90 15// initial votes: all 4 yes -> tie 2-2 -> winner=s1 (lexicographic tie-break) 16// bob changes s1 to no LATER (2026-07-09) -> s1 1-1, s2 2 -> winner=s2 (latest-wins) 17// 18// Rows: 19// 1 fixture-cal-loads alice+bob calendars load via the real organ (new=2 each) 20// 2 group-load 9 records (3 MEMBER + 2 SLOT + 4 VOTE) new=9 seg-6303 21// 3 idempotent-reload new=0 dup_instore=9 (law 10) 22// 4 findtime-members g1 has members=2 (carol is g2 -- roster isolation) candidates=4 23// 5 findtime-morning-slot 08:00-09:00 fits=1 24// 6 findtime-gap-slot 12:00-13:00 fits=1 (between-meetings gap found) 25// 7 findtime-evening-slot 16:00-22:00 fits=6 26// 8 findtime-dur90 2 days dur=90 -> candidates=3 (short windows honestly dropped) 27// 9 recurring-blocks 07-11 free window ENDS 15:00 at bob's recurring gym 28// 10 tally-tie-lexicographic winner=s1 yes=2 on the 2-2 tie 29// 11 tally-latest-wins after bob's later no: s1 yes=1 no=1, winner=s2 yes=2 30// 12 findtime-determinism byte-identical twice 31// 13 loud-fail-unknown-gid findtime ghost -> exit 1 [negative control] 32// 14 loud-fail-bad-date findtime from=2026-13-99 -> exit 1 [negative control] 33// 15 loud-fail-bad-vote VOTE maybe -> load exit 1 [negative control] 34// Evidence: VIZSLA-GRP-GATE -> stdout + knowledge/status/vizsla_gate.log; exit 0 iff 15/15. 35// spec: knowledge/research/2026-06-22-vizsla-sclass-roadmap.md license_tier: ORIGINAL 36import "nx_syscalls.nx" 37import "nx_gate_verdict.nx" 38 39func gg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 40func gg_p(s: *u8) -> i64 { sys_write(1, s, gg_slen(s)); return 0 } 41 42func gg_cat(dst: *u8, off: i64, s: *u8) -> i64 { 43 var i: i64 = 0 44 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 45 return off + i 46} 47 48func gg_catn(dst: *u8, off: i64, v: i64) -> i64 { 49 var o: i64 = off 50 var m: i64 = v 51 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m } 52 let t: *u8 = sys_mmap(28) 53 var k: i64 = 0 54 if m == 0 { t[0] = 48 as u8; k = 1 } 55 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 56 var i: i64 = 0 57 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 } 58 return o + k 59} 60 61func gg_write(path: *u8, content: *u8) -> i64 { 62 let fd: i64 = sys_openat_wr(path, 0x1a4) 63 if fd < 0 { return 0 - 1 } 64 sys_write(fd, content, gg_slen(content)) 65 sys_close(fd) 66 return 0 67} 68 69func gg_readall(path: *u8, szout: *i64) -> *u8 { 70 let fd: i64 = sys_openat_rd(path) 71 if fd < 0 { szout[0] = 0 - 1; return 0 as *u8 } 72 let sz: i64 = sys_lseek(fd, 0, 2) 73 sys_lseek(fd, 0, 0) 74 let buf: *u8 = sys_mmap(sz + 64) 75 var got: i64 = 0 76 var n: i64 = 1 77 while n > 0 { 78 n = sys_read(fd, (buf as i64 + got) as *u8, 65536) 79 if n > 0 { got = got + n } 80 } 81 sys_close(fd) 82 szout[0] = got 83 return buf 84} 85 86func gg_runv(elf: *u8, args: *i64, outpath: *u8) -> i64 { 87 let pid: i64 = sys_fork() 88 if pid == 0 { 89 if (outpath as i64) != 0 { 90 let ofd: i64 = sys_openat_wr(outpath, 0x1a4) 91 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } 92 } 93 let argv: *i64 = sys_mmap(128) as *i64 94 argv[0] = elf as i64 95 var i: i64 = 0 96 var go: i64 = 1 97 while go == 1 { 98 if args[i] == 0 { go = 0 } else { 99 argv[i + 1] = args[i] 100 i = i + 1 101 } 102 } 103 argv[i + 1] = 0 104 let envp: *i64 = sys_mmap(16) as *i64 105 envp[0] = 0 106 sys_execve(elf, argv, envp) 107 sys_exit(127) 108 } 109 let st: *i64 = sys_mmap(16) as *i64 110 sys_wait4(pid, st, 0) 111 let sig: i64 = st[0] & 0x7f 112 if sig != 0 { return 128 + sig } 113 return (st[0] >> 8) & 0xff 114} 115 116func gg_has(path: *u8, needle: *u8) -> i64 { 117 let szp: *i64 = sys_mmap(16) as *i64 118 let b: *u8 = gg_readall(path, szp) 119 let sz: i64 = szp[0] 120 let n: i64 = gg_slen(needle) 121 if sz < n { return 0 } 122 var i: i64 = 0 123 while i + n <= sz { 124 var ok: i64 = 1 125 var j: i64 = 0 126 while j < n { 127 if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 } 128 } 129 if ok == 1 { return 1 } 130 i = i + 1 131 } 132 return 0 133} 134 135func gg_fileeq(p1: *u8, p2: *u8) -> i64 { 136 let s1: *i64 = sys_mmap(16) as *i64 137 let s2: *i64 = sys_mmap(16) as *i64 138 let b1: *u8 = gg_readall(p1, s1) 139 let b2: *u8 = gg_readall(p2, s2) 140 if s1[0] != s2[0] { return 0 } 141 if s1[0] <= 0 { return 0 } 142 var i: i64 = 0 143 while i < s1[0] { 144 if b1[i] != b2[i] { return 0 } 145 i = i + 1 146 } 147 return 1 148} 149 150func gg_row(name: *u8, pass: i64) -> i64 { 151 gg_p("ROW " as *u8) 152 gg_p(name) 153 if pass == 1 { gg_p(" PASS\n" as *u8) } else { gg_p(" FAIL\n" as *u8) } 154 return pass 155} 156 157func gg_args(a1: *u8, a2: *u8, a3: *u8, a4: *u8, a5: *u8, a6: *u8, a7: *u8, a8: *u8) -> *i64 { 158 let a: *i64 = sys_mmap(128) as *i64 159 a[0] = a1 as i64 160 a[1] = a2 as i64 161 a[2] = a3 as i64 162 a[3] = a4 as i64 163 a[4] = a5 as i64 164 a[5] = a6 as i64 165 a[6] = a7 as i64 166 a[7] = a8 as i64 167 a[8] = 0 168 return a 169} 170 171func gg_ensure(elf: *u8, organ: *u8) -> i64 { 172 let pr: i64 = sys_openat_rd(elf) 173 if pr >= 0 { sys_close(pr); return 0 } 174 gg_p(" instrument missing -> rebuilding via durable runner\n" as *u8) 175 gg_runv("_offc/nx_sov_build_run.elf" as *u8, gg_args(organ, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_rebuild.out" as *u8) 176 return 0 177} 178 179func gg_mkpfx(tag: *u8, us: i64) -> *u8 { 180 let pfx: *u8 = sys_mmap(128) 181 var po: i64 = 0 182 po = gg_cat(pfx, po, tag) 183 po = gg_catn(pfx, po, us) 184 po = gg_cat(pfx, po, "-" as *u8) 185 pfx[po] = 0 as u8 186 return pfx 187} 188 189func main(argc: i64, argv: *i64) -> i64 { 190 gg_p("=== VIZSLA GROUP GATE: find-a-time intersection + poll tally KATs (hand-computed) ===\n" as *u8) 191 let cal: *u8 = "buildroot/_build/nx_vizsla_calendar.sov.elf" as *u8 192 let grp: *u8 = "buildroot/_build/nx_vizsla_group.sov.elf" as *u8 193 gg_ensure(cal, "nx_vizsla_calendar" as *u8) 194 gg_ensure(grp, "nx_vizsla_group" as *u8) 195 196 let us: i64 = sys_now_us() 197 let pfxA: *u8 = gg_mkpfx("/tmp/vzgA" as *u8, us) 198 let pfxB: *u8 = gg_mkpfx("/tmp/vzgB" as *u8, us) 199 let pfxG: *u8 = gg_mkpfx("/tmp/vzgG" as *u8, us) 200 201 gg_write("/tmp/vzg_calA.txt" as *u8, "EVENT a1 2026-07-10 540 60 planning\nEVENT a2 2026-07-10 780 60 lunch\n" as *u8) 202 gg_write("/tmp/vzg_calB.txt" as *u8, "EVENT b1 2026-07-10 600 120 work\nRRULE gym 2026-07-10 900 60 DAILY 1 2 gym\n" as *u8) 203 204 var pass: i64 = 0 205 var r: i64 = 0 206 207 // row 1: member calendars load through the REAL calendar organ 208 let rcA: i64 = gg_runv(cal, gg_args("load" as *u8, "/tmp/vzg_calA.txt" as *u8, pfxA, "6301" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_lA.txt" as *u8) 209 let rcB: i64 = gg_runv(cal, gg_args("load" as *u8, "/tmp/vzg_calB.txt" as *u8, pfxB, "6302" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_lB.txt" as *u8) 210 r = 0 211 if rcA == 0 { if rcB == 0 { 212 if gg_has("/tmp/vzg_lA.txt" as *u8, "VIZSLA-CAL-LOAD scanned=2 new=2" as *u8) == 1 { 213 if gg_has("/tmp/vzg_lB.txt" as *u8, "VIZSLA-CAL-LOAD scanned=2 new=2" as *u8) == 1 { r = 1 } 214 } 215 } } 216 pass = pass + gg_row("fixture-cal-loads" as *u8, r) 217 218 // group file (dynamic: carries the real member cal prefixes) 219 let gf: *u8 = sys_mmap(4096) 220 var go2: i64 = 0 221 go2 = gg_cat(gf, go2, "MEMBER g1 alice " as *u8) 222 go2 = gg_cat(gf, go2, pfxA) 223 go2 = gg_cat(gf, go2, "\nMEMBER g1 bob " as *u8) 224 go2 = gg_cat(gf, go2, pfxB) 225 go2 = gg_cat(gf, go2, "\nMEMBER g2 carol /tmp/vzg-none-" as *u8) 226 go2 = gg_cat(gf, go2, "\nSLOT p1 s1 2026-07-10 960 90\nSLOT p1 s2 2026-07-11 480 90\nVOTE p1 s1 alice yes 2026-07-08\nVOTE p1 s1 bob yes 2026-07-08\nVOTE p1 s2 alice yes 2026-07-08\nVOTE p1 s2 bob yes 2026-07-08\n" as *u8) 227 gf[go2] = 0 as u8 228 gg_write("/tmp/vzg_grp.txt" as *u8, gf) 229 230 // row 2: group load 231 let rc2: i64 = gg_runv(grp, gg_args("load" as *u8, "/tmp/vzg_grp.txt" as *u8, pfxG, "6303" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_r2.txt" as *u8) 232 r = 0 233 if rc2 == 0 { 234 if gg_has("/tmp/vzg_r2.txt" as *u8, "VIZSLA-GRP-LOAD scanned=9 new=9 dup_infile=0 dup_instore=0 segment=seg-6303" as *u8) == 1 { r = 1 } 235 } 236 pass = pass + gg_row("group-load" as *u8, r) 237 238 // row 3: idempotent reload 239 let rc3: i64 = gg_runv(grp, gg_args("load" as *u8, "/tmp/vzg_grp.txt" as *u8, pfxG, "6304" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_r3.txt" as *u8) 240 r = 0 241 if rc3 == 0 { 242 if gg_has("/tmp/vzg_r3.txt" as *u8, "VIZSLA-GRP-LOAD scanned=9 new=0 dup_infile=0 dup_instore=9 segment=none" as *u8) == 1 { r = 1 } 243 } 244 pass = pass + gg_row("idempotent-reload" as *u8, r) 245 246 // row 4: findtime members + candidate count (dur=60, 07-10, bounds 08:00-22:00) 247 let rc4: i64 = gg_runv(grp, gg_args("findtime" as *u8, pfxG, "g1" as *u8, "2026-07-10" as *u8, "2026-07-10" as *u8, "60" as *u8, "480" as *u8, "1320" as *u8), "/tmp/vzg_r4.txt" as *u8) 248 r = 0 249 if rc4 == 0 { 250 if gg_has("/tmp/vzg_r4.txt" as *u8, "VIZSLA-GRP-FIND-VERDICT gid=g1 members=2 days=1 dur=60 candidates=4" as *u8) == 1 { r = 1 } 251 } 252 pass = pass + gg_row("findtime-members" as *u8, r) 253 254 // row 5: morning window before everything 255 r = gg_has("/tmp/vzg_r4.txt" as *u8, "VIZSLA-GRP-SLOT gid=g1 date=2026-07-10 start=08:00 end=09:00 fits=1" as *u8) 256 pass = pass + gg_row("findtime-morning-slot" as *u8, r) 257 258 // row 6: the between-meetings gap 259 r = gg_has("/tmp/vzg_r4.txt" as *u8, "VIZSLA-GRP-SLOT gid=g1 date=2026-07-10 start=12:00 end=13:00 fits=1" as *u8) 260 pass = pass + gg_row("findtime-gap-slot" as *u8, r) 261 262 // row 7: evening window 263 r = gg_has("/tmp/vzg_r4.txt" as *u8, "VIZSLA-GRP-SLOT gid=g1 date=2026-07-10 start=16:00 end=22:00 fits=6" as *u8) 264 pass = pass + gg_row("findtime-evening-slot" as *u8, r) 265 266 // row 8: dur=90 across two days -> short windows drop, candidates=3 267 let rc8: i64 = gg_runv(grp, gg_args("findtime" as *u8, pfxG, "g1" as *u8, "2026-07-10" as *u8, "2026-07-11" as *u8, "90" as *u8, "480" as *u8, "1320" as *u8), "/tmp/vzg_r8.txt" as *u8) 268 r = 0 269 if rc8 == 0 { 270 if gg_has("/tmp/vzg_r8.txt" as *u8, "VIZSLA-GRP-FIND-VERDICT gid=g1 members=2 days=2 dur=90 candidates=3" as *u8) == 1 { r = 1 } 271 } 272 pass = pass + gg_row("findtime-dur90" as *u8, r) 273 274 // row 9: recurring gym occurrence bounds the 07-11 free window at 15:00 275 let rc9: i64 = gg_runv(grp, gg_args("findtime" as *u8, pfxG, "g1" as *u8, "2026-07-11" as *u8, "2026-07-11" as *u8, "60" as *u8, "480" as *u8, "1320" as *u8), "/tmp/vzg_r9.txt" as *u8) 276 r = 0 277 if rc9 == 0 { 278 if gg_has("/tmp/vzg_r9.txt" as *u8, "VIZSLA-GRP-SLOT gid=g1 date=2026-07-11 start=08:00 end=15:00 fits=7" as *u8) == 1 { r = 1 } 279 } 280 pass = pass + gg_row("recurring-blocks" as *u8, r) 281 282 // row 10: tally on the 2-2 tie -> lexicographic winner s1 283 let rc10: i64 = gg_runv(grp, gg_args("tally" as *u8, pfxG, "p1" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_r10.txt" as *u8) 284 r = 0 285 if rc10 == 0 { 286 if gg_has("/tmp/vzg_r10.txt" as *u8, "VIZSLA-GRP-TALLY-VERDICT pid=p1 slots=2 votes=4 winner=s1 yes=2" as *u8) == 1 { r = 1 } 287 } 288 pass = pass + gg_row("tally-tie-lexicographic" as *u8, r) 289 290 // row 11: bob flips s1 to no on a LATER date -> latest-wins, winner s2 291 gg_write("/tmp/vzg_chg.txt" as *u8, "VOTE p1 s1 bob no 2026-07-09\n" as *u8) 292 gg_runv(grp, gg_args("load" as *u8, "/tmp/vzg_chg.txt" as *u8, pfxG, "6305" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_l11.txt" as *u8) 293 let rc11: i64 = gg_runv(grp, gg_args("tally" as *u8, pfxG, "p1" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_r11.txt" as *u8) 294 r = 0 295 if rc11 == 0 { 296 if gg_has("/tmp/vzg_r11.txt" as *u8, "VIZSLA-GRP-TALLY pid=p1 slot=s1 date=2026-07-10 start=16:00 yes=1 no=1" as *u8) == 1 { 297 if gg_has("/tmp/vzg_r11.txt" as *u8, "VIZSLA-GRP-TALLY-VERDICT pid=p1 slots=2 votes=4 winner=s2 yes=2" as *u8) == 1 { r = 1 } 298 } 299 } 300 pass = pass + gg_row("tally-latest-wins" as *u8, r) 301 302 // row 12: determinism 303 gg_runv(grp, gg_args("findtime" as *u8, pfxG, "g1" as *u8, "2026-07-10" as *u8, "2026-07-10" as *u8, "60" as *u8, "480" as *u8, "1320" as *u8), "/tmp/vzg_r12.txt" as *u8) 304 r = gg_fileeq("/tmp/vzg_r4.txt" as *u8, "/tmp/vzg_r12.txt" as *u8) 305 pass = pass + gg_row("findtime-determinism" as *u8, r) 306 307 // row 13: unknown gid (negative control) 308 let rc13: i64 = gg_runv(grp, gg_args("findtime" as *u8, pfxG, "ghost" as *u8, "2026-07-10" as *u8, "2026-07-10" as *u8, "60" as *u8, "480" as *u8, "1320" as *u8), "/tmp/vzg_r13.txt" as *u8) 309 r = 0 310 if rc13 == 1 { r = 1 } 311 pass = pass + gg_row("loud-fail-unknown-gid" as *u8, r) 312 313 // row 14: bad date (negative control) 314 let rc14: i64 = gg_runv(grp, gg_args("findtime" as *u8, pfxG, "g1" as *u8, "2026-13-99" as *u8, "2026-07-10" as *u8, "60" as *u8, "480" as *u8, "1320" as *u8), "/tmp/vzg_r14.txt" as *u8) 315 r = 0 316 if rc14 == 1 { r = 1 } 317 pass = pass + gg_row("loud-fail-bad-date" as *u8, r) 318 319 // row 15: bad vote value (negative control) 320 gg_write("/tmp/vzg_badv.txt" as *u8, "VOTE p1 s1 alice maybe 2026-07-08\n" as *u8) 321 let rc15: i64 = gg_runv(grp, gg_args("load" as *u8, "/tmp/vzg_badv.txt" as *u8, pfxG, "6306" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzg_r15.txt" as *u8) 322 r = 0 323 if rc15 == 1 { r = 1 } 324 pass = pass + gg_row("loud-fail-bad-vote" as *u8, r) 325 326 let permil: i64 = (pass * 1000) / 15 327 let logfd: i64 = sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4) 328 var fdi: i64 = 0 329 while fdi < 2 { 330 var fd: i64 = 1 331 if fdi == 1 { fd = logfd } 332 if fd > 0 { 333 let line: *u8 = sys_mmap(256) 334 var o: i64 = 0 335 o = gg_cat(line, o, "VIZSLA-GRP-GATE epoch=" as *u8) 336 o = gg_catn(line, o, sys_now_realtime_sec()) 337 o = gg_cat(line, o, " rows=15 pass=" as *u8) 338 o = gg_catn(line, o, pass) 339 o = gg_cat(line, o, " permil=" as *u8) 340 o = gg_catn(line, o, permil) 341 if pass == 15 { 342 o = gg_cat(line, o, " verdict=GREEN\n" as *u8) 343 } else { 344 o = gg_cat(line, o, " verdict=RED\n" as *u8) 345 } 346 sys_write(fd, line, o) 347 } 348 fdi = fdi + 1 349 } 350 if logfd > 0 { sys_close(logfd) } 351 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 352 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 353 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 354 let ctr__dry: *i64 = gv_ctr() 355 ctr__dry[0] = pass 356 ctr__dry[1] = 15 357 let rc__dry: i64 = gv_verdict("VIZSLA-GROUP-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 358 sys_exit(rc__dry) 359 return rc__dry 360}