code wiki / _hdl_build / nx_vizsla_group_gate.nx
nx_vizsla_group_gate.nx source
↩ module page · 352 lines · 15608 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"
37
38func gg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
39func gg_p(s: *u8) -> i64 { sys_write(1, s, gg_slen(s)); return 0 }
40
41func gg_cat(dst: *u8, off: i64, s: *u8) -> i64 {
42 var i: i64 = 0
43 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
44 return off + i
45}
46
47func gg_catn(dst: *u8, off: i64, v: i64) -> i64 {
48 var o: i64 = off
49 var m: i64 = v
50 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
51 let t: *u8 = sys_mmap(28)
52 var k: i64 = 0
53 if m == 0 { t[0] = 48 as u8; k = 1 }
54 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
55 var i: i64 = 0
56 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
57 return o + k
58}
59
60func gg_write(path: *u8, content: *u8) -> i64 {
61 let fd: i64 = sys_openat_wr(path, 0x1a4)
62 if fd < 0 { return 0 - 1 }
63 sys_write(fd, content, gg_slen(content))
64 sys_close(fd)
65 return 0
66}
67
68func gg_readall(path: *u8, szout: *i64) -> *u8 {
69 let fd: i64 = sys_openat_rd(path)
70 if fd < 0 { szout[0] = 0 - 1; return 0 as *u8 }
71 let sz: i64 = sys_lseek(fd, 0, 2)
72 sys_lseek(fd, 0, 0)
73 let buf: *u8 = sys_mmap(sz + 64)
74 var got: i64 = 0
75 var n: i64 = 1
76 while n > 0 {
77 n = sys_read(fd, (buf as i64 + got) as *u8, 65536)
78 if n > 0 { got = got + n }
79 }
80 sys_close(fd)
81 szout[0] = got
82 return buf
83}
84
85func gg_runv(elf: *u8, args: *i64, outpath: *u8) -> i64 {
86 let pid: i64 = sys_fork()
87 if pid == 0 {
88 if (outpath as i64) != 0 {
89 let ofd: i64 = sys_openat_wr(outpath, 0x1a4)
90 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) }
91 }
92 let argv: *i64 = sys_mmap(128) as *i64
93 argv[0] = elf as i64
94 var i: i64 = 0
95 var go: i64 = 1
96 while go == 1 {
97 if args[i] == 0 { go = 0 } else {
98 argv[i + 1] = args[i]
99 i = i + 1
100 }
101 }
102 argv[i + 1] = 0
103 let envp: *i64 = sys_mmap(16) as *i64
104 envp[0] = 0
105 sys_execve(elf, argv, envp)
106 sys_exit(127)
107 }
108 let st: *i64 = sys_mmap(16) as *i64
109 sys_wait4(pid, st, 0)
110 let sig: i64 = st[0] & 0x7f
111 if sig != 0 { return 128 + sig }
112 return (st[0] >> 8) & 0xff
113}
114
115func gg_has(path: *u8, needle: *u8) -> i64 {
116 let szp: *i64 = sys_mmap(16) as *i64
117 let b: *u8 = gg_readall(path, szp)
118 let sz: i64 = szp[0]
119 let n: i64 = gg_slen(needle)
120 if sz < n { return 0 }
121 var i: i64 = 0
122 while i + n <= sz {
123 var ok: i64 = 1
124 var j: i64 = 0
125 while j < n {
126 if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 }
127 }
128 if ok == 1 { return 1 }
129 i = i + 1
130 }
131 return 0
132}
133
134func gg_fileeq(p1: *u8, p2: *u8) -> i64 {
135 let s1: *i64 = sys_mmap(16) as *i64
136 let s2: *i64 = sys_mmap(16) as *i64
137 let b1: *u8 = gg_readall(p1, s1)
138 let b2: *u8 = gg_readall(p2, s2)
139 if s1[0] != s2[0] { return 0 }
140 if s1[0] <= 0 { return 0 }
141 var i: i64 = 0
142 while i < s1[0] {
143 if b1[i] != b2[i] { return 0 }
144 i = i + 1
145 }
146 return 1
147}
148
149func gg_row(name: *u8, pass: i64) -> i64 {
150 gg_p("ROW " as *u8)
151 gg_p(name)
152 if pass == 1 { gg_p(" PASS\n" as *u8) } else { gg_p(" FAIL\n" as *u8) }
153 return pass
154}
155
156func gg_args(a1: *u8, a2: *u8, a3: *u8, a4: *u8, a5: *u8, a6: *u8, a7: *u8, a8: *u8) -> *i64 {
157 let a: *i64 = sys_mmap(128) as *i64
158 a[0] = a1 as i64
159 a[1] = a2 as i64
160 a[2] = a3 as i64
161 a[3] = a4 as i64
162 a[4] = a5 as i64
163 a[5] = a6 as i64
164 a[6] = a7 as i64
165 a[7] = a8 as i64
166 a[8] = 0
167 return a
168}
169
170func gg_ensure(elf: *u8, organ: *u8) -> i64 {
171 let pr: i64 = sys_openat_rd(elf)
172 if pr >= 0 { sys_close(pr); return 0 }
173 gg_p(" instrument missing -> rebuilding via durable runner\n" as *u8)
174 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)
175 return 0
176}
177
178func gg_mkpfx(tag: *u8, us: i64) -> *u8 {
179 let pfx: *u8 = sys_mmap(128)
180 var po: i64 = 0
181 po = gg_cat(pfx, po, tag)
182 po = gg_catn(pfx, po, us)
183 po = gg_cat(pfx, po, "-" as *u8)
184 pfx[po] = 0 as u8
185 return pfx
186}
187
188func main(argc: i64, argv: *i64) -> i64 {
189 gg_p("=== VIZSLA GROUP GATE: find-a-time intersection + poll tally KATs (hand-computed) ===\n" as *u8)
190 let cal: *u8 = "/tmp/nx_vizsla_calendar.sov.elf" as *u8
191 let grp: *u8 = "/tmp/nx_vizsla_group.sov.elf" as *u8
192 gg_ensure(cal, "nx_vizsla_calendar" as *u8)
193 gg_ensure(grp, "nx_vizsla_group" as *u8)
194
195 let us: i64 = sys_now_us()
196 let pfxA: *u8 = gg_mkpfx("/tmp/vzgA" as *u8, us)
197 let pfxB: *u8 = gg_mkpfx("/tmp/vzgB" as *u8, us)
198 let pfxG: *u8 = gg_mkpfx("/tmp/vzgG" as *u8, us)
199
200 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)
201 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)
202
203 var pass: i64 = 0
204 var r: i64 = 0
205
206 // row 1: member calendars load through the REAL calendar organ
207 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)
208 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)
209 r = 0
210 if rcA == 0 { if rcB == 0 {
211 if gg_has("/tmp/vzg_lA.txt" as *u8, "VIZSLA-CAL-LOAD scanned=2 new=2" as *u8) == 1 {
212 if gg_has("/tmp/vzg_lB.txt" as *u8, "VIZSLA-CAL-LOAD scanned=2 new=2" as *u8) == 1 { r = 1 }
213 }
214 } }
215 pass = pass + gg_row("fixture-cal-loads" as *u8, r)
216
217 // group file (dynamic: carries the real member cal prefixes)
218 let gf: *u8 = sys_mmap(4096)
219 var go2: i64 = 0
220 go2 = gg_cat(gf, go2, "MEMBER g1 alice " as *u8)
221 go2 = gg_cat(gf, go2, pfxA)
222 go2 = gg_cat(gf, go2, "\nMEMBER g1 bob " as *u8)
223 go2 = gg_cat(gf, go2, pfxB)
224 go2 = gg_cat(gf, go2, "\nMEMBER g2 carol /tmp/vzg-none-" as *u8)
225 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)
226 gf[go2] = 0 as u8
227 gg_write("/tmp/vzg_grp.txt" as *u8, gf)
228
229 // row 2: group load
230 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)
231 r = 0
232 if rc2 == 0 {
233 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 }
234 }
235 pass = pass + gg_row("group-load" as *u8, r)
236
237 // row 3: idempotent reload
238 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)
239 r = 0
240 if rc3 == 0 {
241 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 }
242 }
243 pass = pass + gg_row("idempotent-reload" as *u8, r)
244
245 // row 4: findtime members + candidate count (dur=60, 07-10, bounds 08:00-22:00)
246 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)
247 r = 0
248 if rc4 == 0 {
249 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 }
250 }
251 pass = pass + gg_row("findtime-members" as *u8, r)
252
253 // row 5: morning window before everything
254 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)
255 pass = pass + gg_row("findtime-morning-slot" as *u8, r)
256
257 // row 6: the between-meetings gap
258 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)
259 pass = pass + gg_row("findtime-gap-slot" as *u8, r)
260
261 // row 7: evening window
262 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)
263 pass = pass + gg_row("findtime-evening-slot" as *u8, r)
264
265 // row 8: dur=90 across two days -> short windows drop, candidates=3
266 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)
267 r = 0
268 if rc8 == 0 {
269 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 }
270 }
271 pass = pass + gg_row("findtime-dur90" as *u8, r)
272
273 // row 9: recurring gym occurrence bounds the 07-11 free window at 15:00
274 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)
275 r = 0
276 if rc9 == 0 {
277 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 }
278 }
279 pass = pass + gg_row("recurring-blocks" as *u8, r)
280
281 // row 10: tally on the 2-2 tie -> lexicographic winner s1
282 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)
283 r = 0
284 if rc10 == 0 {
285 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 }
286 }
287 pass = pass + gg_row("tally-tie-lexicographic" as *u8, r)
288
289 // row 11: bob flips s1 to no on a LATER date -> latest-wins, winner s2
290 gg_write("/tmp/vzg_chg.txt" as *u8, "VOTE p1 s1 bob no 2026-07-09\n" as *u8)
291 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)
292 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)
293 r = 0
294 if rc11 == 0 {
295 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 {
296 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 }
297 }
298 }
299 pass = pass + gg_row("tally-latest-wins" as *u8, r)
300
301 // row 12: determinism
302 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)
303 r = gg_fileeq("/tmp/vzg_r4.txt" as *u8, "/tmp/vzg_r12.txt" as *u8)
304 pass = pass + gg_row("findtime-determinism" as *u8, r)
305
306 // row 13: unknown gid (negative control)
307 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)
308 r = 0
309 if rc13 == 1 { r = 1 }
310 pass = pass + gg_row("loud-fail-unknown-gid" as *u8, r)
311
312 // row 14: bad date (negative control)
313 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)
314 r = 0
315 if rc14 == 1 { r = 1 }
316 pass = pass + gg_row("loud-fail-bad-date" as *u8, r)
317
318 // row 15: bad vote value (negative control)
319 gg_write("/tmp/vzg_badv.txt" as *u8, "VOTE p1 s1 alice maybe 2026-07-08\n" as *u8)
320 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)
321 r = 0
322 if rc15 == 1 { r = 1 }
323 pass = pass + gg_row("loud-fail-bad-vote" as *u8, r)
324
325 let permil: i64 = (pass * 1000) / 15
326 let logfd: i64 = sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4)
327 var fdi: i64 = 0
328 while fdi < 2 {
329 var fd: i64 = 1
330 if fdi == 1 { fd = logfd }
331 if fd > 0 {
332 let line: *u8 = sys_mmap(256)
333 var o: i64 = 0
334 o = gg_cat(line, o, "VIZSLA-GRP-GATE epoch=" as *u8)
335 o = gg_catn(line, o, sys_now_realtime_sec())
336 o = gg_cat(line, o, " rows=15 pass=" as *u8)
337 o = gg_catn(line, o, pass)
338 o = gg_cat(line, o, " permil=" as *u8)
339 o = gg_catn(line, o, permil)
340 if pass == 15 {
341 o = gg_cat(line, o, " verdict=GREEN\n" as *u8)
342 } else {
343 o = gg_cat(line, o, " verdict=RED\n" as *u8)
344 }
345 sys_write(fd, line, o)
346 }
347 fdi = fdi + 1
348 }
349 if logfd > 0 { sys_close(logfd) }
350 if pass == 15 { return 0 }
351 return 1
352}