code wiki / _hdl_build / nx_vizsla_digest_gate.nx
nx_vizsla_digest_gate.nx source
↩ module page · 366 lines · 18800 B
1// nx_vizsla_digest_gate.nx -- VIZSLA V5 gate: the daily DIGEST composes the
2// blessed nx_vizsla_relate (brief) + nx_vizsla_notes (draftdue) over fixture
3// data and is proven to consolidate + aggregate them correctly. No mocks: it
4// loads real seg_store fixtures via the real organs and runs the real digest.
5//
6// fixtures (today=2026-06-14):
7// relate: mom(inner,06-20) alex(close,03-15) sam(network,12-01) pat(close,-);
8// TOUCH mom 06-10, alex 02-01; OBLIG OWE alex book-loan, DUE pat loan-50;
9// THANKS mom 06-12, alex 05-01.
10// brief => followups=3 (alex DUE, sam/pat NEW), birthdays=1 (mom in 6d),
11// thankyous=2 (mom PENDING, alex OVERDUE), obligations=2.
12// notes: e1 mom birthday 06-20, e2 alex surgery 07-01, e3 sam wedding 06-10;
13// n1 birthday BEFORE 7, n2 surgery BEFORE 3, n3 wedding AFTER 2;
14// occasions: birthday win 7, wedding win 90 -> n1 DUE + n3 DUE => drafted=2.
15// => VIZSLA-DIGEST-VERDICT followups=3 birthdays=1 thankyous=2 obligations=2 notes_drafted=2
16//
17// Rows:
18// 1 loud-fail-missing-conf digest on absent conf => exit 1
19// 2 loud-fail-missing-key conf missing NOTES_PREFIX => exit 1
20// 3 digest-relationships FOLLOWUP alex + BIRTHDAY mom present
21// 4 digest-notes-drafts the wedding draft prose present
22// 5 digest-verdict-aggregates consolidated verdict 3/1/2/2 + notes_drafted=2
23// 6 digest-determinism byte-identical twice
24// Evidence: VIZSLA-DIGEST-GATE -> stdout + knowledge/status/vizsla_gate.log; exit 0 iff 6/6.
25// Tamper: bogus instrument argv[1] => all rows FAIL => RED.
26// spec: knowledge/specs/2026-06-10-nishi-vizsla-ladder.md license_tier: ORIGINAL
27import "nx_syscalls.nx"
28import "nx_gate_verdict.nx"
29
30func rg_slen(s: *u8) -> i64 {
31 var n: i64 = 0
32 while s[n] != (0 as u8) { n = n + 1 }
33 return n
34}
35
36func rg_p(s: *u8) -> i64 {
37 sys_write(1, s, rg_slen(s))
38 return 0
39}
40
41func rg_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 rg_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 rg_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, rg_slen(content))
64 sys_close(fd)
65 return 0
66}
67
68func rg_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 rg_run(elf: *u8, a1: *u8, a2: *u8, a3: *u8, a4: *u8, 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(64) as *i64
93 argv[0] = elf as i64
94 var i: i64 = 1
95 if (a1 as i64) != 0 { argv[i] = a1 as i64; i = i + 1 }
96 if (a2 as i64) != 0 { argv[i] = a2 as i64; i = i + 1 }
97 if (a3 as i64) != 0 { argv[i] = a3 as i64; i = i + 1 }
98 if (a4 as i64) != 0 { argv[i] = a4 as i64; i = i + 1 }
99 argv[i] = 0
100 let envp: *i64 = sys_mmap(16) as *i64
101 envp[0] = 0
102 sys_execve(elf, argv, envp)
103 sys_exit(127)
104 }
105 let st: *i64 = sys_mmap(16) as *i64
106 sys_wait4(pid, st, 0)
107 let sig: i64 = st[0] & 0x7f
108 if sig != 0 { return 128 + sig }
109 return (st[0] >> 8) & 0xff
110}
111
112func rg_has(path: *u8, needle: *u8) -> i64 {
113 let szp: *i64 = sys_mmap(16) as *i64
114 let b: *u8 = rg_readall(path, szp)
115 let sz: i64 = szp[0]
116 let n: i64 = rg_slen(needle)
117 if sz < n { return 0 }
118 var i: i64 = 0
119 while i + n <= sz {
120 var ok: i64 = 1
121 var j: i64 = 0
122 while j < n {
123 if b[i + j] != needle[j] { ok = 0; j = n } else { j = j + 1 }
124 }
125 if ok == 1 { return 1 }
126 i = i + 1
127 }
128 return 0
129}
130
131func rg_fileeq(p1: *u8, p2: *u8) -> i64 {
132 let s1: *i64 = sys_mmap(16) as *i64
133 let s2: *i64 = sys_mmap(16) as *i64
134 let b1: *u8 = rg_readall(p1, s1)
135 let b2: *u8 = rg_readall(p2, s2)
136 if s1[0] != s2[0] { return 0 }
137 if s1[0] <= 0 { return 0 }
138 var i: i64 = 0
139 while i < s1[0] {
140 if b1[i] != b2[i] { return 0 }
141 i = i + 1
142 }
143 return 1
144}
145
146func rg_row(name: *u8, pass: i64) -> i64 {
147 rg_p("ROW " as *u8)
148 rg_p(name)
149 if pass == 1 { rg_p(" PASS\n" as *u8) } else { rg_p(" FAIL\n" as *u8) }
150 return pass
151}
152
153func main(argc: i64, argv: *i64) -> i64 {
154 rg_p("=== VIZSLA DIGEST GATE: the daily digest composes brief + notes-due ===\n" as *u8)
155 var rb: *u8 = "buildroot/_build/nx_vizsla_digest.sov.elf" as *u8
156 if argc > 1 { rb = argv[1] as *u8 }
157 let pr: i64 = sys_openat_rd(rb)
158 if pr >= 0 { sys_close(pr) }
159 else {
160 rg_p(" instrument missing -> rebuilding via durable runner\n" as *u8)
161 rg_run("_offc/nx_sov_build_run.elf" as *u8, "nx_vizsla_digest" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, "/tmp/dgg_rebuild.out" as *u8)
162 }
163
164 // epoch-unique virgin store prefixes
165 let rpfx: *u8 = sys_mmap(128)
166 var ro: i64 = 0
167 ro = rg_cat(rpfx, ro, "/tmp/dggR" as *u8); ro = rg_catn(rpfx, ro, sys_now_us()); ro = rg_cat(rpfx, ro, "-" as *u8); rpfx[ro] = 0 as u8
168 let npfx: *u8 = sys_mmap(128)
169 var no: i64 = 0
170 no = rg_cat(npfx, no, "/tmp/dggN" as *u8); no = rg_catn(npfx, no, sys_now_us()); no = rg_cat(npfx, no, "-" as *u8); npfx[no] = 0 as u8
171
172 rg_write("/tmp/dgg_contacts.txt" as *u8, "CONF soon_days 14\nTIER inner 30\nTIER close 90\nTIER network 180\nCONTACT mom Mom inner 06-20\nCONTACT alex Alex-Mentor close 03-15\nCONTACT sam Sam-Colleague network 12-01\nCONTACT pat Pat-Friend close -\n" as *u8)
173 rg_write("/tmp/dgg_relog.txt" as *u8, "TOUCH 2026-06-10 mom weekly-call\nTOUCH 2026-02-01 alex lunch\nOBLIGATION 2026-05-01 OWE alex book-loan 0 borrowed-book\nOBLIGATION 2026-05-05 DUE pat loan-50 5000 lent-cash\nTHANKS 2026-06-12 mom birthday-gift\nTHANKS 2026-05-01 alex referral\n" as *u8)
174 rg_write("/tmp/dgg_nlog.txt" as *u8, "EVENT e1 2026-06-20 mom birthday card-gift\nEVENT e2 2026-07-01 alex surgery recovery\nEVENT e3 2026-06-10 sam wedding congrats\nNOTE n1 e1 BEFORE 7 card signature:img-mom\nNOTE n2 e2 BEFORE 3 text voice:vm-alex\nNOTE n3 e3 AFTER 2 card handwritten:scan-sam\n" as *u8)
175 rg_write("/tmp/dgg_nconf.txt" as *u8, "CONF window_days 3\nOCCASION birthday BEFORE 3 7 arrive-by-the-day\nOCCASION wedding AFTER 0 90 thank-you-within-3-months\nOCCASION surgery BEFORE 2 7 before-procedure\n" as *u8)
176 rg_write("/tmp/dgg_ntmpl.txt" as *u8, "TMPL birthday BEFORE Happy early birthday, {contact}! Wishing you a wonderful day on {date}. Enclosed: {personal}\nTMPL wedding AFTER Dear {contact}, thank you for including us in your wedding -- it was a joy. Enclosed: {personal}\n" as *u8)
177
178 // load fixtures into the two stores via the blessed organs
179 rg_run("_offc/nx_vizsla_relate.elf" as *u8, "load" as *u8, "/tmp/dgg_relog.txt" as *u8, rpfx, "6001" as *u8, "/tmp/dgg_rl.txt" as *u8)
180 rg_run("_offc/nx_vizsla_notes.elf" as *u8, "load" as *u8, "/tmp/dgg_nlog.txt" as *u8, npfx, "6001" as *u8, "/tmp/dgg_nl.txt" as *u8)
181 // bills store + fixtures (for the optional bills section)
182 let bpfx: *u8 = sys_mmap(128)
183 var bpo: i64 = 0
184 bpo = rg_cat(bpfx, bpo, "/tmp/dggB" as *u8); bpo = rg_catn(bpfx, bpo, sys_now_us()); bpo = rg_cat(bpfx, bpo, "-" as *u8); bpfx[bpo] = 0 as u8
185 rg_write("/tmp/dgg_bills.txt" as *u8, "CONF soon_days 7\nBILL rent Landlord 180000 1 MONTHLY MANUAL\nBILL electric PowerCo 12000 15 MONTHLY MANUAL\nBILL netflix Netflix 1599 20 MONTHLY AUTO\nBILL water CityWater 4500 10 MONTHLY MANUAL\nBILL phone TelCo 6000 25 MONTHLY MANUAL\n" as *u8)
186 rg_write("/tmp/dgg_bllog.txt" as *u8, "PAID 2026-06-02 rent 180000 june-rent\nPAID 2026-05-20 netflix 1599 may-auto\n" as *u8)
187 rg_run("_offc/nx_vizsla_bills.elf" as *u8, "load" as *u8, "/tmp/dgg_bllog.txt" as *u8, bpfx, "5001" as *u8, "/tmp/dgg_bl.txt" as *u8)
188
189 // good digest.conf (built with the generated prefixes)
190 let conf: *u8 = sys_mmap(2048)
191 var co: i64 = 0
192 co = rg_cat(conf, co, "RELATE_PREFIX " as *u8); co = rg_cat(conf, co, rpfx); co = rg_cat(conf, co, "\n" as *u8)
193 co = rg_cat(conf, co, "RELATE_CONTACTS /tmp/dgg_contacts.txt\n" as *u8)
194 co = rg_cat(conf, co, "NOTES_PREFIX " as *u8); co = rg_cat(conf, co, npfx); co = rg_cat(conf, co, "\n" as *u8)
195 co = rg_cat(conf, co, "NOTES_CONF /tmp/dgg_nconf.txt\n" as *u8)
196 co = rg_cat(conf, co, "NOTES_TEMPLATES /tmp/dgg_ntmpl.txt\n" as *u8)
197 conf[co] = 0 as u8
198 rg_write("/tmp/dgg.conf" as *u8, conf)
199 // a second conf that ALSO enables bills (= the good conf + BILLS keys)
200 let bconf: *u8 = sys_mmap(2048)
201 var bco: i64 = 0
202 bco = rg_cat(bconf, bco, conf)
203 bco = rg_cat(bconf, bco, "BILLS_PREFIX " as *u8); bco = rg_cat(bconf, bco, bpfx); bco = rg_cat(bconf, bco, "\n" as *u8)
204 bco = rg_cat(bconf, bco, "BILLS_FILE /tmp/dgg_bills.txt\n" as *u8)
205 bconf[bco] = 0 as u8
206 rg_write("/tmp/dgg_bills.conf" as *u8, bconf)
207 // engagement-partner fixtures: calendar + plan + venue stores via the BLESSED organs
208 let cpfx: *u8 = sys_mmap(128)
209 var cpo: i64 = 0
210 cpo = rg_cat(cpfx, cpo, "/tmp/dggC" as *u8); cpo = rg_catn(cpfx, cpo, sys_now_us()); cpo = rg_cat(cpfx, cpo, "-" as *u8); cpfx[cpo] = 0 as u8
211 rg_write("/tmp/dgg_cal.txt" as *u8, "EVENT mtg 2026-06-14 600 60 standup-mtg\n" as *u8)
212 rg_run("_offc/nx_vizsla_calendar.elf" as *u8, "load" as *u8, "/tmp/dgg_cal.txt" as *u8, cpfx, "7001" as *u8, "/tmp/dgg_cl.txt" as *u8)
213 let ppfx: *u8 = sys_mmap(128)
214 var ppo: i64 = 0
215 ppo = rg_cat(ppfx, ppo, "/tmp/dggP" as *u8); ppo = rg_catn(ppfx, ppo, sys_now_us()); ppo = rg_cat(ppfx, ppo, "-" as *u8); ppfx[ppo] = 0 as u8
216 rg_write("/tmp/dgg_plan.txt" as *u8, "TASK dg venue2 jason 2026-06-16 60 5 - book-venue2\n" as *u8)
217 rg_run("_offc/nx_vizsla_plan.elf" as *u8, "load" as *u8, "/tmp/dgg_plan.txt" as *u8, ppfx, "7002" as *u8, "/tmp/dgg_pl.txt" as *u8)
218 let vpfx: *u8 = sys_mmap(128)
219 var vpo: i64 = 0
220 vpo = rg_cat(vpfx, vpo, "/tmp/dggV" as *u8); vpo = rg_catn(vpfx, vpo, sys_now_us()); vpo = rg_cat(vpfx, vpo, "-" as *u8); vpfx[vpo] = 0 as u8
221 rg_write("/tmp/dgg_ven.txt" as *u8, "REQ dgparty 10 20000 2026-06-20 600 120\nVENUE dgparty spot-x 12 15000 555-9 corner-hall\nSTAGE 2026-06-10 dgparty spot-x contacted\n" as *u8)
222 rg_run("_offc/nx_vizsla_venue.elf" as *u8, "load" as *u8, "/tmp/dgg_ven.txt" as *u8, vpfx, "7003" as *u8, "/tmp/dgg_vl.txt" as *u8)
223 // the ENGAGE conf = good conf + calendar/reminders/plan/venue sections
224 let econf: *u8 = sys_mmap(4096)
225 var eco: i64 = 0
226 eco = rg_cat(econf, eco, conf)
227 eco = rg_cat(econf, eco, "CAL_PREFIX " as *u8); eco = rg_cat(econf, eco, cpfx); eco = rg_cat(econf, eco, "\n" as *u8)
228 eco = rg_cat(econf, eco, "REMIND_CONTACTS /tmp/dgg_contacts.txt\n" as *u8)
229 eco = rg_cat(econf, eco, "REMIND_LEADS 6,0\n" as *u8)
230 eco = rg_cat(econf, eco, "PLAN_PREFIX " as *u8); eco = rg_cat(econf, eco, ppfx); eco = rg_cat(econf, eco, "\n" as *u8)
231 eco = rg_cat(econf, eco, "PLAN_NAME dg\n" as *u8)
232 eco = rg_cat(econf, eco, "VENUE_PREFIX " as *u8); eco = rg_cat(econf, eco, vpfx); eco = rg_cat(econf, eco, "\n" as *u8)
233 eco = rg_cat(econf, eco, "VENUE_EVENT dgparty\n" as *u8)
234 econf[eco] = 0 as u8
235 rg_write("/tmp/dgg_engage.conf" as *u8, econf)
236
237 // bad conf: omit NOTES_PREFIX
238 let bad: *u8 = sys_mmap(2048)
239 var bo: i64 = 0
240 bo = rg_cat(bad, bo, "RELATE_PREFIX " as *u8); bo = rg_cat(bad, bo, rpfx); bo = rg_cat(bad, bo, "\n" as *u8)
241 bo = rg_cat(bad, bo, "RELATE_CONTACTS /tmp/dgg_contacts.txt\n" as *u8)
242 bo = rg_cat(bad, bo, "NOTES_CONF /tmp/dgg_nconf.txt\n" as *u8)
243 bo = rg_cat(bad, bo, "NOTES_TEMPLATES /tmp/dgg_ntmpl.txt\n" as *u8)
244 bad[bo] = 0 as u8
245 rg_write("/tmp/dgg_bad.conf" as *u8, bad)
246
247 var pass: i64 = 0
248 var r: i64 = 0
249
250 // row 1: loud-fail on missing conf
251 let rc1: i64 = rg_run(rb, "digest" as *u8, "/tmp/dgg_NOPE.conf" as *u8, "2026-06-14" as *u8, 0 as *u8, "/tmp/dgg_o1.txt" as *u8)
252 r = 0
253 if rc1 == 1 { r = 1 }
254 pass = pass + rg_row("loud-fail-missing-conf" as *u8, r)
255
256 // row 2: loud-fail on a conf missing a required key
257 let rc2: i64 = rg_run(rb, "digest" as *u8, "/tmp/dgg_bad.conf" as *u8, "2026-06-14" as *u8, 0 as *u8, "/tmp/dgg_o2.txt" as *u8)
258 r = 0
259 if rc2 == 1 { r = 1 }
260 pass = pass + rg_row("loud-fail-missing-key" as *u8, r)
261
262 // row 3-6: the real digest
263 let rc3: i64 = rg_run(rb, "digest" as *u8, "/tmp/dgg.conf" as *u8, "2026-06-14" as *u8, 0 as *u8, "/tmp/dgg_dig.txt" as *u8)
264 r = 0
265 if rc3 == 0 {
266 if rg_has("/tmp/dgg_dig.txt" as *u8, " FOLLOWUP contact=alex days=133 (DUE)" as *u8) == 1 {
267 if rg_has("/tmp/dgg_dig.txt" as *u8, " BIRTHDAY contact=mom on=06-20 in=6d" as *u8) == 1 { r = 1 }
268 }
269 }
270 pass = pass + rg_row("digest-relationships" as *u8, r)
271
272 r = rg_has("/tmp/dgg_dig.txt" as *u8, "Dear sam, thank you for including us in your wedding" as *u8)
273 pass = pass + rg_row("digest-notes-drafts" as *u8, r)
274
275 r = rg_has("/tmp/dgg_dig.txt" as *u8, "VIZSLA-DIGEST-VERDICT followups=3 birthdays=1 thankyous=2 obligations=2 notes_drafted=2" as *u8)
276 pass = pass + rg_row("digest-verdict-aggregates" as *u8, r)
277
278 rg_run(rb, "digest" as *u8, "/tmp/dgg.conf" as *u8, "2026-06-14" as *u8, 0 as *u8, "/tmp/dgg_dig2.txt" as *u8)
279 r = rg_fileeq("/tmp/dgg_dig.txt" as *u8, "/tmp/dgg_dig2.txt" as *u8)
280 pass = pass + rg_row("digest-determinism" as *u8, r)
281
282 // row 7: the bills-enabled conf adds a BILLS section
283 let rc7: i64 = rg_run(rb, "digest" as *u8, "/tmp/dgg_bills.conf" as *u8, "2026-06-14" as *u8, 0 as *u8, "/tmp/dgg_digb.txt" as *u8)
284 r = 0
285 if rc7 == 0 {
286 if rg_has("/tmp/dgg_digb.txt" as *u8, "VIZSLA-BILL id=water payee=CityWater amount=4500 due=2026-06-10 autopay=MANUAL state=OVERDUE" as *u8) == 1 { r = 1 }
287 }
288 pass = pass + rg_row("digest-bills-section" as *u8, r)
289
290 // row 8: the consolidated verdict aggregates bills (due/overdue/owed)
291 r = rg_has("/tmp/dgg_digb.txt" as *u8, "VIZSLA-DIGEST-VERDICT followups=3 birthdays=1 thankyous=2 obligations=2 notes_drafted=2 bills_due=2 bills_overdue=1 bills_owed_cents=24099" as *u8)
292 pass = pass + rg_row("digest-bills-verdict" as *u8, r)
293
294 // row 9: bills are OPTIONAL -- the no-bills conf produces NO bills fields
295 r = 0
296 if rg_has("/tmp/dgg_dig.txt" as *u8, "bills_owed_cents" as *u8) == 0 {
297 if rg_has("/tmp/dgg_dig.txt" as *u8, "notes_drafted=2" as *u8) == 1 { r = 1 }
298 }
299 pass = pass + rg_row("digest-bills-optional" as *u8, r)
300
301 // rows 10-14: the ENGAGEMENT-PARTNER digest (calendar + reminders + plan + venue)
302 let rc10: i64 = rg_run(rb, "digest" as *u8, "/tmp/dgg_engage.conf" as *u8, "2026-06-14" as *u8, 0 as *u8, "/tmp/dgg_dige.txt" as *u8)
303 r = 0
304 if rc10 == 0 {
305 if rg_has("/tmp/dgg_dige.txt" as *u8, "== CALENDAR TODAY ==" as *u8) == 1 {
306 if rg_has("/tmp/dgg_dige.txt" as *u8, "VIZSLA-CAL-EVENT date=2026-06-14 start=10:00 end=11:00 dur=60 id=mtg title=standup-mtg" as *u8) == 1 { r = 1 }
307 }
308 }
309 pass = pass + rg_row("digest-engage-calendar" as *u8, r)
310
311 r = 0
312 if rg_has("/tmp/dgg_dige.txt" as *u8, "VIZSLA-REM-DUE kind=birthday id=mom date=2026-06-20 in=6 title=Mom" as *u8) == 1 {
313 if rg_has("/tmp/dgg_dige.txt" as *u8, "VIZSLA-REM-DUE kind=event id=mtg date=2026-06-14 in=0 title=standup-mtg" as *u8) == 1 { r = 1 }
314 }
315 pass = pass + rg_row("digest-engage-reminders" as *u8, r)
316
317 r = 0
318 if rg_has("/tmp/dgg_dige.txt" as *u8, "VIZSLA-PLAN-TASK plan=dg id=venue2 owner=jason due=2026-06-16 state=READY urg=4 imp=5 score=50 late=0 title=book-venue2" as *u8) == 1 {
319 if rg_has("/tmp/dgg_dige.txt" as *u8, "VIZSLA-VEN-CAND event=dgparty id=spot-x stage=contacted cap=12 cost=15000 score=85 over_budget=0 too_small=0 contact=555-9 name=corner-hall" as *u8) == 1 { r = 1 }
320 }
321 pass = pass + rg_row("digest-engage-plan-venue" as *u8, r)
322
323 r = rg_has("/tmp/dgg_dige.txt" as *u8, "VIZSLA-DIGEST-VERDICT followups=3 birthdays=1 thankyous=2 obligations=2 notes_drafted=2 cal_events=1 cal_free_min=1380 reminders_due=2 reminders_birthdays=1 plan_ready=1 plan_blocked=0 plan_late=0 venues=1 venue_booked=0" as *u8)
324 pass = pass + rg_row("digest-engage-verdict" as *u8, r)
325
326 r = 0
327 if rg_has("/tmp/dgg_dig.txt" as *u8, "cal_events=" as *u8) == 0 {
328 if rg_has("/tmp/dgg_dig.txt" as *u8, "reminders_due=" as *u8) == 0 { r = 1 }
329 }
330 pass = pass + rg_row("digest-engage-optional" as *u8, r)
331
332 let permil: i64 = (pass * 1000) / 14
333 let logfd: i64 = sys_openat_append("knowledge/status/vizsla_gate.log" as *u8, 0x1a4)
334 var fdi: i64 = 0
335 while fdi < 2 {
336 var fd: i64 = 1
337 if fdi == 1 { fd = logfd }
338 if fd > 0 {
339 let line: *u8 = sys_mmap(256)
340 var o: i64 = 0
341 o = rg_cat(line, o, "VIZSLA-DIGEST-GATE epoch=" as *u8)
342 o = rg_catn(line, o, sys_now_realtime_sec())
343 o = rg_cat(line, o, " rows=14 pass=" as *u8)
344 o = rg_catn(line, o, pass)
345 o = rg_cat(line, o, " permil=" as *u8)
346 o = rg_catn(line, o, permil)
347 if pass == 14 {
348 o = rg_cat(line, o, " verdict=GREEN\n" as *u8)
349 } else {
350 o = rg_cat(line, o, " verdict=RED\n" as *u8)
351 }
352 sys_write(fd, line, o)
353 }
354 fdi = fdi + 1
355 }
356 if logfd > 0 { sys_close(logfd) }
357 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
358 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
359 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
360 let ctr__dry: *i64 = gv_ctr()
361 ctr__dry[0] = pass
362 ctr__dry[1] = 14
363 let rc__dry: i64 = gv_verdict("VIZSLA-DIGEST-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
364 sys_exit(rc__dry)
365 return rc__dry
366}