code wiki / _hdl_build / nx_vizsla_ics_gate.nx
nx_vizsla_ics_gate.nx source
↩ module page · 436 lines · 16784 B
1// nx_vizsla_ics_gate.nx -- VIZSLA R-CAL.4 gate: RFC 5545 .ics EXPORT is gate-proven against
2// construction-known fixtures. GENUINE COMPOSITION: forks the blessed calendar organ to LOAD the
3// store, then the ics organ to EXPORT it -- the gate never fabricates store bytes itself.
4//
5// fixture (loaded via nx_vizsla_calendar, seg-6201):
6// EVENT launch 2026-06-20 10:00 +90 title "pizza,night;launch" (TEXT-escape exercise)
7// EVENT ride 2026-07-03 08:00 +120 title 86-char token (75-octet folding exercise)
8// EVENT far 2026-09-01 08:00 +60 out-of-window (exclusion exercise)
9// RRULE standup 2026-06-01 WEEKLY/2 x6 -> native RRULE passthrough
10// RRULE bday 2024-02-29 YEARLY/1 x50 -> intersects window via last-occurrence (2073)
11// window 2026-06-01..2026-07-31 => events=2 rules=2 => 4 VEVENTs.
12//
13// Rows:
14// 1 export-ok exit 0 + VIZSLA-ICS-VERDICT events=2 rules=2
15// 2 vcalendar-frame BEGIN:VCALENDAR + VERSION:2.0 + PRODID + END:VCALENDAR
16// 3 crlf-strict every LF preceded by CR (RFC5545 line ends), >=10 lines
17// 4 vevent-count exactly 4 BEGIN:VEVENT
18// 5 dtstart-dtend launch DTSTART:20260620T100000 + DTEND:20260620T113000
19// 6 uid-stable UID:launch-20260620@nishi.vizsla
20// 7 rrule-weekly RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=6
21// 8 rrule-yearly RRULE:FREQ=YEARLY;INTERVAL=1;COUNT=50
22// 9 summary-escaping SUMMARY:pizza\,night\;launch (backslash-escaped , and ;)
23// 10 fold-75 no physical line >75 octets + a CRLF+space continuation + folded=1
24// 11 window-exclusion UID:far- ABSENT (out-of-window event not exported)
25// 12 export-determinism two exports byte-identical (no clocks in the artifact)
26// 13 loud-fail-bad-date export from=2026-13-99 => exit 1 [negative control]
27// 14 loud-fail-unwritable export into a nonexistent dir => exit 1 [negative control]
28// Evidence: VIZSLA-ICS-GATE -> stdout + knowledge/status/vizsla_gate.log; exit 0 iff 14/14.
29// spec: knowledge/research/2026-06-22-vizsla-sclass-roadmap.md license_tier: ORIGINAL
30import "nx_syscalls.nx"
31import "nx_gate_verdict.nx"
32
33func ig_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
34func ig_p(s: *u8) -> i64 { sys_write(1, s, ig_slen(s)); return 0 }
35
36func ig_cat(dst: *u8, off: i64, s: *u8) -> i64 {
37 var i: i64 = 0
38 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 }
39 return off + i
40}
41
42func ig_catn(dst: *u8, off: i64, v: i64) -> i64 {
43 var o: i64 = off
44 var m: i64 = v
45 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
46 let t: *u8 = sys_mmap(28)
47 var k: i64 = 0
48 if m == 0 { t[0] = 48 as u8; k = 1 }
49 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
50 var i: i64 = 0
51 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 }
52 return o + k
53}
54
55func ig_write(path: *u8, content: *u8) -> i64 {
56 let fd: i64 = sys_openat_wr(path, 0x1a4)
57 if fd < 0 { return 0 - 1 }
58 sys_write(fd, content, ig_slen(content))
59 sys_close(fd)
60 return 0
61}
62
63func ig_readall(path: *u8, szout: *i64) -> *u8 {
64 let fd: i64 = sys_openat_rd(path)
65 if fd < 0 { szout[0] = 0 - 1; return 0 as *u8 }
66 let sz: i64 = sys_lseek(fd, 0, 2)
67 sys_lseek(fd, 0, 0)
68 let buf: *u8 = sys_mmap(sz + 64)
69 var got: i64 = 0
70 var n: i64 = 1
71 while n > 0 {
72 n = sys_read(fd, (buf as i64 + got) as *u8, 65536)
73 if n > 0 { got = got + n }
74 }
75 sys_close(fd)
76 szout[0] = got
77 return buf
78}
79
80func ig_runv(elf: *u8, args: *i64, outpath: *u8) -> i64 {
81 let pid: i64 = sys_fork()
82 if pid == 0 {
83 if (outpath as i64) != 0 {
84 let ofd: i64 = sys_openat_wr(outpath, 0x1a4)
85 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) }
86 }
87 let argv: *i64 = sys_mmap(128) as *i64
88 argv[0] = elf as i64
89 var i: i64 = 0
90 var go: i64 = 1
91 while go == 1 {
92 if args[i] == 0 { go = 0 } else {
93 argv[i + 1] = args[i]
94 i = i + 1
95 }
96 }
97 argv[i + 1] = 0
98 let envp: *i64 = sys_mmap(16) as *i64
99 envp[0] = 0
100 sys_execve(elf, argv, envp)
101 sys_exit(127)
102 }
103 let st: *i64 = sys_mmap(16) as *i64
104 sys_wait4(pid, st, 0)
105 let sig: i64 = st[0] & 0x7f
106 if sig != 0 { return 128 + sig }
107 return (st[0] >> 8) & 0xff
108}
109
110func ig_has(path: *u8, needle: *u8) -> i64 {
111 let szp: *i64 = sys_mmap(16) as *i64
112 let b: *u8 = ig_readall(path, szp)
113 let sz: i64 = szp[0]
114 let n: i64 = ig_slen(needle)
115 if sz < n { return 0 }
116 var i: i64 = 0
117 while i + n <= sz {
118 var ok: i64 = 1
119 var j: i64 = 0
120 while j < n {
121 if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 }
122 }
123 if ok == 1 { return 1 }
124 i = i + 1
125 }
126 return 0
127}
128
129func ig_count(path: *u8, needle: *u8) -> i64 {
130 let szp: *i64 = sys_mmap(16) as *i64
131 let b: *u8 = ig_readall(path, szp)
132 let sz: i64 = szp[0]
133 let n: i64 = ig_slen(needle)
134 var cnt: i64 = 0
135 if sz < n { return 0 }
136 var i: i64 = 0
137 while i + n <= sz {
138 var ok: i64 = 1
139 var j: i64 = 0
140 while j < n {
141 if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 }
142 }
143 if ok == 1 { cnt = cnt + 1; i = i + n } else { i = i + 1 }
144 }
145 return cnt
146}
147
148// every LF preceded by CR; returns line count if strict, else -1
149func ig_crlf_lines(path: *u8) -> i64 {
150 let szp: *i64 = sys_mmap(16) as *i64
151 let b: *u8 = ig_readall(path, szp)
152 let sz: i64 = szp[0]
153 if sz <= 0 { return 0 - 1 }
154 var lines: i64 = 0
155 var i: i64 = 0
156 while i < sz {
157 if b[i] == (10 as u8) {
158 if i == 0 { return 0 - 1 }
159 if b[i - 1] != (13 as u8) { return 0 - 1 }
160 lines = lines + 1
161 }
162 i = i + 1
163 }
164 return lines
165}
166
167// longest physical line in octets EXCLUDING the CRLF terminator
168func ig_maxline(path: *u8) -> i64 {
169 let szp: *i64 = sys_mmap(16) as *i64
170 let b: *u8 = ig_readall(path, szp)
171 let sz: i64 = szp[0]
172 var mx: i64 = 0
173 var cur: i64 = 0
174 var i: i64 = 0
175 while i < sz {
176 if b[i] == (10 as u8) {
177 var l: i64 = cur - 1
178 if l < 0 { l = 0 }
179 if l > mx { mx = l }
180 cur = 0
181 } else {
182 cur = cur + 1
183 }
184 i = i + 1
185 }
186 if cur > mx { mx = cur }
187 return mx
188}
189
190func ig_fileeq(p1: *u8, p2: *u8) -> i64 {
191 let s1: *i64 = sys_mmap(16) as *i64
192 let s2: *i64 = sys_mmap(16) as *i64
193 let b1: *u8 = ig_readall(p1, s1)
194 let b2: *u8 = ig_readall(p2, s2)
195 if s1[0] != s2[0] { return 0 }
196 if s1[0] <= 0 { return 0 }
197 var i: i64 = 0
198 while i < s1[0] {
199 if b1[i] != b2[i] { return 0 }
200 i = i + 1
201 }
202 return 1
203}
204
205func ig_row(name: *u8, pass: i64) -> i64 {
206 ig_p("ROW " as *u8)
207 ig_p(name)
208 if pass == 1 { ig_p(" PASS\n" as *u8) } else { ig_p(" FAIL\n" as *u8) }
209 return pass
210}
211
212func ig_args(a1: *u8, a2: *u8, a3: *u8, a4: *u8, a5: *u8) -> *i64 {
213 let a: *i64 = sys_mmap(64) as *i64
214 a[0] = a1 as i64
215 a[1] = a2 as i64
216 a[2] = a3 as i64
217 a[3] = a4 as i64
218 a[4] = a5 as i64
219 a[5] = 0
220 return a
221}
222
223func ig_ensure(elf: *u8, organ: *u8) -> i64 {
224 let pr: i64 = sys_openat_rd(elf)
225 if pr >= 0 { sys_close(pr); return 0 }
226 ig_p(" instrument missing -> rebuilding via durable runner\n" as *u8)
227 ig_runv("_offc/nx_sov_build_run.elf" as *u8, ig_args(organ, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8), "/tmp/vzi_rebuild.out" as *u8)
228 return 0
229}
230
231func main(argc: i64, argv: *i64) -> i64 {
232 ig_p("=== VIZSLA ICS GATE: RFC 5545 export KATs (frame/CRLF/UID/RRULE/escape/fold) ===\n" as *u8)
233 let cal: *u8 = "buildroot/_build/nx_vizsla_calendar.sov.elf" as *u8
234 let ics: *u8 = "buildroot/_build/nx_vizsla_ics.sov.elf" as *u8
235 ig_ensure(cal, "nx_vizsla_calendar" as *u8)
236 ig_ensure(ics, "nx_vizsla_ics" as *u8)
237
238 let pfx: *u8 = sys_mmap(128)
239 var po: i64 = 0
240 po = ig_cat(pfx, po, "/tmp/vziE" as *u8)
241 po = ig_catn(pfx, po, sys_now_us())
242 po = ig_cat(pfx, po, "-" as *u8)
243 pfx[po] = 0 as u8
244
245 let fx: *u8 = "EVENT launch 2026-06-20 600 90 pizza,night;launch\nEVENT ride 2026-07-03 480 120 the-really-long-annual-friends-camping-trip-planning-weekend-at-the-lake-house-edition\nEVENT far 2026-09-01 480 60 out-of-window\nRRULE standup 2026-06-01 540 30 WEEKLY 2 6 biweekly-standup\nRRULE bday 2024-02-29 540 60 YEARLY 1 50 leap-birthday\n" as *u8
246 ig_write("/tmp/vzi_fx.txt" as *u8, fx)
247
248 var pass: i64 = 0
249 var r: i64 = 0
250
251 let rcl: i64 = ig_runv(cal, ig_args("load" as *u8, "/tmp/vzi_fx.txt" as *u8, pfx, "6201" as *u8, 0 as *u8), "/tmp/vzi_load.txt" as *u8)
252 if rcl != 0 { ig_p("FIXTURE LOAD FAILED -- gate cannot proceed\n" as *u8) }
253
254 // row 1: export ok + verdict counts
255 let outp: *u8 = "/tmp/vzi_out.ics" as *u8
256 let rc1: i64 = ig_runv(ics, ig_args("export" as *u8, pfx, "2026-06-01" as *u8, "2026-07-31" as *u8, outp), "/tmp/vzi_r1.txt" as *u8)
257 r = 0
258 if rc1 == 0 {
259 if ig_has("/tmp/vzi_r1.txt" as *u8, "VIZSLA-ICS-VERDICT events=2 rules=2" as *u8) == 1 { r = 1 }
260 }
261 pass = pass + ig_row("export-ok" as *u8, r)
262
263 // row 2: VCALENDAR frame
264 r = 0
265 if ig_has(outp, "BEGIN:VCALENDAR" as *u8) == 1 {
266 if ig_has(outp, "VERSION:2.0" as *u8) == 1 {
267 if ig_has(outp, "PRODID:-//Nishi//Vizsla Calendar//EN" as *u8) == 1 {
268 if ig_has(outp, "END:VCALENDAR" as *u8) == 1 { r = 1 }
269 }
270 }
271 }
272 pass = pass + ig_row("vcalendar-frame" as *u8, r)
273
274 // row 3: strict CRLF line ends
275 let nl: i64 = ig_crlf_lines(outp)
276 r = 0
277 if nl >= 10 { r = 1 }
278 pass = pass + ig_row("crlf-strict" as *u8, r)
279
280 // row 4: exactly 4 VEVENTs
281 r = 0
282 if ig_count(outp, "BEGIN:VEVENT" as *u8) == 4 {
283 if ig_count(outp, "END:VEVENT" as *u8) == 4 { r = 1 }
284 }
285 pass = pass + ig_row("vevent-count" as *u8, r)
286
287 // row 5: DTSTART/DTEND of launch
288 r = 0
289 if ig_has(outp, "DTSTART:20260620T100000" as *u8) == 1 {
290 if ig_has(outp, "DTEND:20260620T113000" as *u8) == 1 { r = 1 }
291 }
292 pass = pass + ig_row("dtstart-dtend" as *u8, r)
293
294 // row 6: stable UID
295 r = ig_has(outp, "UID:launch-20260620@nishi.vizsla" as *u8)
296 pass = pass + ig_row("uid-stable" as *u8, r)
297
298 // row 7: WEEKLY RRULE passthrough
299 r = ig_has(outp, "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=6" as *u8)
300 pass = pass + ig_row("rrule-weekly" as *u8, r)
301
302 // row 8: YEARLY RRULE passthrough (the birthday substrate)
303 r = ig_has(outp, "RRULE:FREQ=YEARLY;INTERVAL=1;COUNT=50" as *u8)
304 pass = pass + ig_row("rrule-yearly" as *u8, r)
305
306 // row 9: TEXT escaping (needle built byte-wise: SUMMARY:pizza\,night\;launch)
307 let esc: *u8 = sys_mmap(64)
308 var eo: i64 = 0
309 eo = ig_cat(esc, eo, "SUMMARY:pizza" as *u8)
310 esc[eo] = 92 as u8; eo = eo + 1
311 eo = ig_cat(esc, eo, ",night" as *u8)
312 esc[eo] = 92 as u8; eo = eo + 1
313 eo = ig_cat(esc, eo, ";launch" as *u8)
314 esc[eo] = 0 as u8
315 r = ig_has(outp, esc)
316 pass = pass + ig_row("summary-escaping" as *u8, r)
317
318 // row 10: 75-octet folding (no long physical line + a CRLF+SPACE continuation + folded=1)
319 let contn: *u8 = sys_mmap(8)
320 contn[0] = 13 as u8
321 contn[1] = 10 as u8
322 contn[2] = 32 as u8
323 contn[3] = 0 as u8
324 r = 0
325 if ig_maxline(outp) <= 75 {
326 if ig_has(outp, contn) == 1 {
327 if ig_has("/tmp/vzi_r1.txt" as *u8, "folded=1" as *u8) == 1 { r = 1 }
328 }
329 }
330 pass = pass + ig_row("fold-75" as *u8, r)
331
332 // row 11: out-of-window event excluded
333 r = 0
334 if ig_has(outp, "UID:far-" as *u8) == 0 { r = 1 }
335 pass = pass + ig_row("window-exclusion" as *u8, r)
336
337 // row 12: determinism (re-export byte-identical)
338 ig_runv(ics, ig_args("export" as *u8, pfx, "2026-06-01" as *u8, "2026-07-31" as *u8, "/tmp/vzi_out2.ics" as *u8), "/tmp/vzi_r12.txt" as *u8)
339 r = ig_fileeq(outp, "/tmp/vzi_out2.ics" as *u8)
340 pass = pass + ig_row("export-determinism" as *u8, r)
341
342 // row 13: loud-fail bad date (negative control)
343 let rc13: i64 = ig_runv(ics, ig_args("export" as *u8, pfx, "2026-13-99" as *u8, "2026-07-31" as *u8, "/tmp/vzi_bad.ics" as *u8), "/tmp/vzi_r13.txt" as *u8)
344 r = 0
345 if rc13 == 1 { r = 1 }
346 pass = pass + ig_row("loud-fail-bad-date" as *u8, r)
347
348 // row 14: loud-fail unwritable out path (negative control)
349 let rc14: i64 = ig_runv(ics, ig_args("export" as *u8, pfx, "2026-06-01" as *u8, "2026-07-31" as *u8, "/tmp/no_such_dir_vzi/out.ics" as *u8), "/tmp/vzi_r14.txt" as *u8)
350 r = 0
351 if rc14 == 1 { r = 1 }
352 pass = pass + ig_row("loud-fail-unwritable" as *u8, r)
353
354 // ===== IMPORT round-trip: the .ics we just exported -> a fresh store the calendar organ reads =====
355 let pfxI: *u8 = sys_mmap(128)
356 var pio: i64 = 0
357 pio = ig_cat(pfxI, pio, "/tmp/vziI" as *u8)
358 pio = ig_catn(pfxI, pio, sys_now_us())
359 pio = ig_cat(pfxI, pio, "-" as *u8)
360 pfxI[pio] = 0 as u8
361
362 // row 15: import the exported .ics -> events=2 rules=2 new=4
363 let rc15: i64 = ig_runv(ics, ig_args("import" as *u8, outp, pfxI, "6301" as *u8, 0 as *u8), "/tmp/vzi_r15.txt" as *u8)
364 r = 0
365 if rc15 == 0 {
366 if ig_has("/tmp/vzi_r15.txt" as *u8, "VIZSLA-ICS-IMPORT events=2 rules=2 new=4 dup_instore=0 segment=seg-6301" as *u8) == 1 { r = 1 }
367 }
368 pass = pass + ig_row("import-ok" as *u8, r)
369
370 // row 16: the imported single event is queryable through the real calendar organ
371 let rc16: i64 = ig_runv(cal, ig_args("day" as *u8, pfxI, "2026-07-03" as *u8, 0 as *u8, 0 as *u8), "/tmp/vzi_r16.txt" as *u8)
372 r = 0
373 if rc16 == 0 {
374 if ig_has("/tmp/vzi_r16.txt" as *u8, "VIZSLA-CAL-EVENT date=2026-07-03 start=08:00 end=10:00 dur=120 id=ride" as *u8) == 1 { r = 1 }
375 }
376 pass = pass + ig_row("import-event-queryable" as *u8, r)
377
378 // row 17: the imported RRULEs expand -- YEARLY birthday (Feb clamp) + WEEKLY interval survive
379 let rc17: i64 = ig_runv(cal, ig_args("expand" as *u8, pfxI, "2026-01-01" as *u8, "2026-07-31" as *u8, 0 as *u8), "/tmp/vzi_r17.txt" as *u8)
380 r = 0
381 if rc17 == 0 {
382 if ig_has("/tmp/vzi_r17.txt" as *u8, "VIZSLA-CAL-OCC id=bday date=2026-02-28 start=09:00 end=10:00 freq=YEARLY" as *u8) == 1 {
383 if ig_has("/tmp/vzi_r17.txt" as *u8, "VIZSLA-CAL-OCC id=standup date=2026-06-15 start=09:00 end=09:30 freq=WEEKLY" as *u8) == 1 { r = 1 }
384 }
385 }
386 pass = pass + ig_row("import-rrule-queryable" as *u8, r)
387
388 // row 18: re-import is CID-idempotent (never-lose additive plane)
389 let rc18: i64 = ig_runv(ics, ig_args("import" as *u8, outp, pfxI, "6302" as *u8, 0 as *u8), "/tmp/vzi_r18.txt" as *u8)
390 r = 0
391 if rc18 == 0 {
392 if ig_has("/tmp/vzi_r18.txt" as *u8, "new=0 dup_instore=4 segment=none" as *u8) == 1 { r = 1 }
393 }
394 pass = pass + ig_row("import-idempotent" as *u8, r)
395
396 // row 19: import missing file (negative control)
397 let rc19: i64 = ig_runv(ics, ig_args("import" as *u8, "/tmp/vzi_nope.ics" as *u8, pfxI, "6303" as *u8, 0 as *u8), "/tmp/vzi_r19.txt" as *u8)
398 r = 0
399 if rc19 == 1 { r = 1 }
400 pass = pass + ig_row("import-loud-fail" as *u8, r)
401
402 let permil: i64 = (pass * 1000) / 19
403 let logfd: i64 = sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4)
404 var fdi: i64 = 0
405 while fdi < 2 {
406 var fd: i64 = 1
407 if fdi == 1 { fd = logfd }
408 if fd > 0 {
409 let line: *u8 = sys_mmap(256)
410 var o: i64 = 0
411 o = ig_cat(line, o, "VIZSLA-ICS-GATE epoch=" as *u8)
412 o = ig_catn(line, o, sys_now_realtime_sec())
413 o = ig_cat(line, o, " rows=19 pass=" as *u8)
414 o = ig_catn(line, o, pass)
415 o = ig_cat(line, o, " permil=" as *u8)
416 o = ig_catn(line, o, permil)
417 if pass == 19 {
418 o = ig_cat(line, o, " verdict=GREEN\n" as *u8)
419 } else {
420 o = ig_cat(line, o, " verdict=RED\n" as *u8)
421 }
422 sys_write(fd, line, o)
423 }
424 fdi = fdi + 1
425 }
426 if logfd > 0 { sys_close(logfd) }
427 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
428 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
429 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
430 let ctr__dry: *i64 = gv_ctr()
431 ctr__dry[0] = pass
432 ctr__dry[1] = 19
433 let rc__dry: i64 = gv_verdict("VIZSLA-ICS-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
434 sys_exit(rc__dry)
435 return rc__dry
436}