code wiki / _hdl_build / nx_evidence_beat.nx

nx_evidence_beat.nx source

↩ module page · 410 lines · 24499 B

1// nx_evidence_beat.nx -- THE CADENCE. Closes the seq1433 half that turns this workstream from a one-shot 2// into an actual loop. 3// 4// ★WHY THIS IS THE KEYSTONE, NOT A CHORE. Everything built this session expires on purpose: evstamps carry 5// an epoch and are refused past the TTL, bite records likewise. That expiry is the whole point -- a verdict 6// that outlives its evidence is the defect this workstream opened by fixing. But expiry without RENEWAL is 7// just a slower way to reach zero: within one TTL every domain silently falls back to UNPROVEN and the 8// board returns to exactly the state it started in. A measurement you never repeat is a measurement you 9// will eventually be lying about. 10// 11// WHAT IT DOES, per invocation: 12// for each domain declaring executable evidence (knowledge/compare/<d>.gates) 13// * if its evstamp is missing or older than the REFRESH threshold -> re-run nx_swcompare_evidence <d> 14// * if any of its declared gates lacks a fresh bite record -> re-run nx_bite_sweep <d> 15// 16// ★REFRESH AT HALF THE TTL, not at expiry. Renewing only once a record has already died guarantees a window 17// in which the board reads UNPROVEN for domains that are fine -- the instrument would manufacture its own 18// false negatives on a timer. Half-life renewal means a single missed beat is survivable. 19// 20// ★BOUNDED WORK BY CONSTRUCTION. Each refresh forks real gates and, for a sweep, rebuilds source repeatedly; 21// an unbounded beat would run for hours and get killed mid-flight, leaving a mutated tree behind. maxwork 22// caps the number of refreshes per invocation and the beat reports what it DEFERRED rather than silently 23// truncating -- a cadence that hides its own backlog is how "green" drifts away from "current". 24// 25// usage: nx_evidence_beat [maxwork] [--dry] (CWD = nxc2 root) 26// exit 0 = nothing overdue, or all attempted work succeeded · 1 = a refresh failed · 2 = usage 27// license_tier: ORIGINAL 28import "nx_syscalls.nx" 29import "nx_artifact_root.nx" 30const EB_MAGIC_4096: i64 = 4096 31const EB_MAGIC_4095: i64 = 4095 32const EB_MAGIC_604800: i64 = 604800 33const EB_MAGIC_1024: i64 = 1024 34 35const EB_DEF_MAXWORK: i64 = 3 36 37func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 38func wn(v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(28); var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 39func wf(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 40func wnf(fd: i64, v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(28); var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(fd,b,k); return 0 } 41 42func eb_read(path: *u8, buf: *u8, cap: i64) -> i64 { 43 let fd: i64 = sys_openat_rd(path) 44 if fd < 0 { return 0 - 1 } 45 var tot: i64 = 0 46 var go: i64 = 1 47 while go == 1 { 48 let n: i64 = sys_read(fd, ((buf as i64)+tot) as *u8, cap - tot) 49 if n <= 0 { go = 0 } else { tot = tot + n; if tot >= cap { go = 0 } } 50 } 51 sys_close(fd) 52 return tot 53} 54func eb_num_after(buf: *u8, n: i64, key: *u8, kl: i64) -> i64 { 55 var i: i64 = 0 56 while i <= n - kl { 57 var j: i64 = 0 58 var m: i64 = 1 59 while j < kl { if buf[i+j] != key[j] { m = 0; j = kl } else { j = j + 1 } } 60 if m == 1 { 61 var p: i64 = i + kl 62 var v: i64 = 0 63 var got: i64 = 0 64 while p < n { let c: i64 = buf[p] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48); got = 1; p = p + 1 } else { p = n } } else { p = n } } 65 if got == 1 { return v } 66 return 0 - 1 67 } 68 i = i + 1 69 } 70 return 0 - 1 71} 72func eb_cat(dst: *u8, off: i64, s: *u8) -> i64 { 73 var o: i64 = off 74 var i: i64 = 0 75 while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } 76 return o 77} 78func eb_catn(dst: *u8, off: i64, domain: *u8, dl: i64) -> i64 { 79 var o: i64 = off 80 var i: i64 = 0 81 while i < dl { dst[o] = domain[i]; o = o + 1; i = i + 1 } 82 return o 83} 84 85// A .gates file holds one line per declared gate. The read cap is DERIVED from the buffer size and 86// never authored a second time -- a cap written as its own literal beside the buffer it guards is 87// the same constant spelled twice, and the two drift. 88const EB_GATES_BYTES: i64 = 65536 89const EB_GATES_CAP: i64 = EB_GATES_BYTES - 1 90const EB_VERDICT_BYTES: i64 = 1024 91const EB_VERDICT_CAP: i64 = EB_VERDICT_BYTES - 1 92 93// ---- EVIDENCE-NEWER-THAN-STAMP: the general repair (2026-08-15) ---- 94// A stamp FREEZES redseen at the moment it is written, but its INPUT -- the bite records under 95// knowledge/status/bite_<gate>.verdict -- is written by a DIFFERENT producer at a DIFFERENT time. 96// When a bite lands after the stamp, the stamp reports fewer proven gates than the evidence on disk 97// already supports, and nothing corrects it until the half-life refresh up to ttl/2 later. 98// MEASURED 2026-08-15 over all 42 domains (coverage_complete=1): 26 sat at redseen=0 while the 99// estate held 109 killed=1 records, and finance alone moved 0 -> 16 on a single re-stamp with no 100// gate re-run differently and no source changed. 101// This trigger is deliberately GENERAL: it fires for bite records written by ANY producer, not only 102// by the sweep this beat runs itself, so a hand-run nx_gate_bite is repaired on the next pass too. 103// It is SELF-LIMITING -- re-stamping makes the stamp epoch newer than every bite, so the condition 104// clears until new evidence actually arrives, and a domain with no bites never triggers it at all. 105// A STAMP THAT PREDATES ITS OWN EVIDENCE UNDERSTATES THE SYSTEM AND READS EXACTLY LIKE VACUITY. 106func eb_evidence_newer(dom: *u8, stamp_ep: i64) -> i64 { 107 var dl: i64 = 0 108 while dom[dl] != (0 as u8) { dl = dl + 1 } 109 let gp: *u8 = sys_mmap(512) 110 var o: i64 = eb_cat(gp, 0, "knowledge/compare/" as *u8) 111 o = eb_catn(gp, o, dom, dl) 112 o = eb_cat(gp, o, ".gates" as *u8) 113 gp[o] = 0 as u8 114 let gb: *u8 = sys_mmap(EB_GATES_BYTES) 115 let gn: i64 = eb_read(gp, gb, EB_GATES_CAP) 116 if gn <= 0 { return 0 } 117 let vp: *u8 = sys_mmap(512) 118 let vb: *u8 = sys_mmap(EB_VERDICT_BYTES) 119 var found: i64 = 0 120 var i: i64 = 0 121 while i < gn { 122 // The line end is found with a SEPARATE flag, never by writing a sentinel into the cursor -- 123 // a loop that exits by clobbering its own index cannot then report where it stopped. 124 var e: i64 = i 125 var eol: i64 = 0 126 while eol == 0 { 127 if e >= gn { eol = 1 } else { 128 if gb[e] == (10 as u8) { eol = 1 } else { e = e + 1 } 129 } 130 } 131 if gb[i] != (35 as u8) { 132 var bar: i64 = 0 - 1 133 var scan: i64 = i 134 while scan < e { 135 if bar < 0 { if gb[scan] == (124 as u8) { bar = scan } } 136 scan = scan + 1 137 } 138 if bar > i { 139 var s: i64 = i 140 var k: i64 = i 141 while k < bar { if gb[k] == (47 as u8) { s = k + 1 } k = k + 1 } 142 var en: i64 = bar 143 if en - s > 4 { if gb[en-4] == (46 as u8) { en = en - 4 } } 144 if en > s { 145 var vo: i64 = eb_cat(vp, 0, "knowledge/status/bite_" as *u8) 146 var c: i64 = s 147 while c < en { vp[vo] = gb[c]; vo = vo + 1; c = c + 1 } 148 vo = eb_cat(vp, vo, ".verdict" as *u8) 149 vp[vo] = 0 as u8 150 let vn: i64 = eb_read(vp, vb, EB_VERDICT_CAP) 151 if vn > 0 { 152 let bep: i64 = eb_num_after(vb, vn, "epoch=" as *u8, 6) 153 if bep > stamp_ep { found = 1 } 154 } 155 } 156 } 157 } 158 i = e + 1 159 } 160 return found 161} 162 163// fork <elf> <arg1> [arg2]; return exit code 164func eb_run2(elf: *u8, a1: *u8, a2: *u8, outpath: *u8) -> i64 { 165 let pid: i64 = sys_fork() 166 if pid == 0 { 167 // MODE_0644, not 0x1a4. The 39-site consolidation swept the DECIMAL spelling (420) and this 168 // hex twin survived it -- the same constant in two bases is two constants to every scanner. 169 let ofd: i64 = sys_openat_wr(outpath, MODE_0644) 170 if ofd >= 0 { sys_dup3(ofd, 1, 0); sys_dup3(ofd, 2, 0) } 171 let argv: *i64 = sys_mmap(48) as *i64 172 argv[0] = elf as i64 173 argv[1] = a1 as i64 174 if (a2 as i64) == 0 { argv[2] = 0 } else { argv[2] = a2 as i64; argv[3] = 0 } 175 let envp: *i64 = sys_mmap(16) as *i64 176 envp[0] = 0 177 sys_execve(elf, argv, envp) 178 sys_exit(127) 179 } 180 let stp: *i64 = sys_mmap(16) as *i64 181 sys_wait4(pid, stp, 0) 182 let sig: i64 = stp[0] & 0x7f 183 if sig != 0 { return 128 + sig } 184 return (stp[0] >> 8) & 0xff 185} 186 187func main(argc: i64, argv: *i64) -> i64 { 188 // Resolution order is argv > conf > compiled default (rule 17). 0 means "nobody has said yet", so a 189 // conf value can still outrank the compiled floor -- initialising straight to the default would let 190 // the code silently beat the config file that exists to hold precisely this number. 191 var maxwork: i64 = 0 192 var argv_maxwork: i64 = 0 193 var dry: i64 = 0 194 if argc > 1 { 195 let a: *u8 = argv[1] as *u8 196 if a[0] == (45 as u8) { dry = 1 } else { 197 maxwork = 0 198 var i: i64 = 0 199 while a[i] != (0 as u8) { maxwork = maxwork*10 + ((a[i] as i64) - 48); i = i + 1 } 200 if maxwork <= 0 { maxwork = EB_DEF_MAXWORK } 201 argv_maxwork = 1 202 } 203 } 204 if argc > 2 { let b: *u8 = argv[2] as *u8; if b[0] == (45 as u8) { dry = 1 } } 205 206 let now: i64 = sys_now_realtime_sec() 207 // ONE policy, read from the same file every other consumer reads (rule 17). 208 let pb: *u8 = sys_mmap(EB_MAGIC_4096) 209 let pn: i64 = eb_read("knowledge/evidence_policy.conf" as *u8, pb, EB_MAGIC_4095) 210 var ttl: i64 = EB_MAGIC_604800 211 if pn > 0 { let v: i64 = eb_num_after(pb, pn, "ttl_sec=" as *u8, 8); if v > 0 { ttl = v } } 212 // THE BUDGET COMES FROM THE SAME POLICY FILE AS THE TTL IT IS DERIVED FROM. It was a compiled 213 // constant of 3 while refresh demand was 44 domains / 14 passes per half-life = 3.15 per pass, so 214 // the beat could not keep up with its own scan even before sweeps: MEASURED 2026-08-15 as 215 // refreshed=3 swept=0 deferred=23, nine domains aged 6.3 days, and smallos/nishios never stamped 216 // because they sort last and the budget was always gone before the scan reached them. 217 // A BUDGET SET BELOW ITS STEADY-STATE DEMAND DOES NOT SLOW A QUEUE DOWN, IT GUARANTEES IT GROWS -- 218 // and it reports a tidy GREEN while doing so, because every pass really did complete its budget. 219 if argv_maxwork == 0 { if pn > 0 { let mw: i64 = eb_num_after(pb, pn, "beat_maxwork=" as *u8, 13); if mw > 0 { maxwork = mw } } } 220 if maxwork <= 0 { maxwork = EB_DEF_MAXWORK } 221 let refresh: i64 = ttl / 2 222 223 w("=== nx_evidence_beat -- renew what is about to expire (half-life refresh) ===\n") 224 w(" ttl="); wn(ttl); w("s refresh_at="); wn(refresh); w("s maxwork="); wn(maxwork) 225 if dry == 1 { w(" MODE=dry-run") } 226 w("\n") 227 228 let evelf: *u8 = sys_mmap(512) 229 let swelf: *u8 = sys_mmap(512) 230 let haveev: i64 = ar_resolve("_offc/nx_swcompare_evidence.elf" as *u8, evelf) 231 let havesw: i64 = ar_resolve("_offc/nx_bite_sweep.elf" as *u8, swelf) 232 if haveev == 0 { w(" CANNOT RESOLVE nx_swcompare_evidence.elf -- promote it first\n"); sys_exit(2); return 2 } 233 234 let dbuf: *u8 = sys_mmap(1 << 16) 235 let fd: i64 = sys_openat_rd("knowledge/compare\x00" as *u8) 236 if fd < 0 { w(" cannot open knowledge/compare\n"); sys_exit(2); return 2 } 237 let outp: *u8 = "knowledge/status/evidence_beat_run.out\x00" as *u8 238 let dom: *u8 = sys_mmap(256) 239 let path: *u8 = sys_mmap(512) 240 var scanned: i64 = 0 241 var refreshed: i64 = 0 242 var swept: i64 = 0 243 var restamped: i64 = 0 244 var deferred: i64 = 0 245 var failed: i64 = 0 246 var work: i64 = 0 247 248 var go: i64 = 1 249 while go == 1 { 250 let nr: i64 = sys_getdents64(fd, dbuf, 1 << 16) 251 if nr <= 0 { go = 0 } else { 252 var pos: i64 = 0 253 while pos < nr { 254 let rec: *u8 = ((dbuf as i64) + pos) as *u8 255 let reclen: i64 = dirent_reclen(rec) 256 let name: *u8 = ((rec as i64) + 19) as *u8 257 var ln: i64 = 0 258 while name[ln] != (0 as u8) { ln = ln + 1 } 259 // only domains that DECLARE executable evidence: <d>.gates 260 var isg: i64 = 0 261 if ln > 6 { 262 let g: *u8 = ".gates\x00" as *u8 263 var m: i64 = 1 264 var q: i64 = 0 265 while q < 6 { if name[ln-6+q] != g[q] { m = 0; q = 6 } else { q = q + 1 } } 266 isg = m 267 } 268 if isg == 1 { 269 let dl: i64 = ln - 6 270 var c: i64 = 0 271 while c < dl { dom[c] = name[c]; c = c + 1 } 272 dom[dl] = 0 as u8 273 scanned = scanned + 1 274 // age of this domain's evstamp 275 var o: i64 = eb_cat(path, 0, "knowledge/status/evstamp_" as *u8) 276 o = eb_catn(path, o, dom, dl) 277 o = eb_cat(path, o, ".verdict" as *u8) 278 path[o] = 0 as u8 279 let sb: *u8 = sys_mmap(EB_MAGIC_1024) 280 let sn: i64 = eb_read(path, sb, 1023) 281 var age: i64 = ttl + 1 282 var stamp_ep: i64 = 0 283 if sn > 0 { let ep: i64 = eb_num_after(sb, sn, "epoch=" as *u8, 6); if ep > 0 { stamp_ep = ep; if now >= ep { age = now - ep } } } 284 // TWO INDEPENDENT REASONS TO RENEW, AND THEY MUST NOT SHARE A MESSAGE: the stamp is 285 // near expiry (TIME), or the evidence underneath it has moved since it was written 286 // (CONTENT). Only the first existed before 2026-08-15, which is why 26 of 42 domains 287 // published a redseen lower than their own bite records already supported. The content 288 // test is asked ONLY when the time test did not fire, so an overdue domain costs no 289 // extra reads and a fresh one costs a handful of small reads and no gate runs. 290 var evnew: i64 = 0 291 if age <= refresh { if stamp_ep > 0 { evnew = eb_evidence_newer(dom, stamp_ep) } } 292 var due: i64 = 0 293 if age > refresh { due = 1 } else { if evnew == 1 { due = 1 } } 294 if due == 1 { 295 // ★THE DRY RUN MUST SPEND THE SAME BUDGET. The first cut incremented the work 296 // counter only on the real path, so --dry listed EVERY overdue domain as if it 297 // would all be done in one pass -- a preview that disagrees with the run it is 298 // previewing is worse than no preview, because it is trusted. 299 if work >= maxwork { 300 deferred = deferred + 1 301 w(" DEFER "); w(dom); w(" age="); wn(age); w("s (budget spent)\n") 302 } else { 303 work = work + 1 304 if evnew == 1 { w(" REFRESH "); w(dom); w(" EVIDENCE-NEWER-THAN-STAMP -> ") } else { w(" REFRESH "); w(dom); w(" age="); wn(age); w("s -> ") } 305 if dry == 1 { w("(dry)\n") } else { 306 let rc: i64 = eb_run2(evelf, dom, 0 as *u8, outp) 307 if rc == 0 { w("MEASURED-HONEST\n") } else { w("RED (exit "); wn(rc); w(")\n"); failed = failed + 1 } 308 refreshed = refreshed + 1 309 // NON-VACUITY RENEWAL: re-read the stamp we just wrote. If fewer gates have 310 // a live bite record than the domain declares, its non-vacuity has aged out 311 // and the sweep must run -- otherwise the beat renews the cheap half of the 312 // evidence and quietly lets the expensive half expire. 313 if havesw == 1 { 314 let s2: *u8 = sys_mmap(EB_MAGIC_1024) 315 let n2: i64 = eb_read(path, s2, 1023) 316 if n2 > 0 { 317 let rs: i64 = eb_num_after(s2, n2, "redseen=" as *u8, 8) 318 let dc: i64 = eb_num_after(s2, n2, "declared=" as *u8, 9) 319 if dc > 0 { if rs < dc { 320 // A SWEEP WHOSE RESULT IS NEVER STAMPED IS WORK PAID FOR AND 321 // THROWN AWAY. The re-stamp is not a separate task -- it is the 322 // second half of this one, so the budget reserves BOTH or the 323 // pass declines to start. Budget-checking the cheap half only 324 // AFTER spending the expensive half discards the sweep's result 325 // at exactly the moment the budget is tightest, which is the 326 // worst possible time to lose it. 327 if work + 2 <= maxwork { 328 work = work + 2 329 w(" SWEEP "); w(dom); w(" redseen="); wn(rs); w("/"); wn(dc); w(" -> ") 330 // 6 -> 16, MEASURED 2026-08-01, not guessed. nx_x25519_kat_gate 331 // returned INCONCLUSIVE at 4 sites and again at 6-equivalent 332 // depth; the KILL landed at site 4 of the NUMERIC-CONSTANT 333 // operator only once the cap allowed 14. Constant-time crypto 334 // exposes few mutable comparisons and its early numeric literals 335 // are structural (array sizes -> uncompilable), so the first 336 // handful of sites are systematically barren for exactly the 337 // KAT/ORACLE class this beat most needs to score. 338 // ★A SITE CAP IS A SAMPLING DECISION: TOO SMALL AND THE SWEEP 339 // MANUFACTURES "INCONCLUSIVE" AND CALLS IT A MEASUREMENT. 340 // Cost is bounded -- the sweep stops at the FIRST kill, so a 341 // gate that bites early still costs the same 1-2 rebuilds. 342 let rc2: i64 = eb_run2(swelf, dom, "16\x00" as *u8, outp) 343 if rc2 == 0 { w("all gates BITE\n") } else { w("not all proven (exit "); wn(rc2); w(")\n") } 344 swept = swept + 1 345 // THE STAMP IS WRITTEN BEFORE THE SWEEP THAT PRODUCES ITS OWN 346 // NON-VACUITY EVIDENCE. Without this re-stamp the sweep's 347 // result is invisible until the next half-life refresh 3.5 348 // days later, so the beat renews the CHEAP half of the 349 // evidence, generates the EXPENSIVE half, and then throws the 350 // expensive half away. 351 // MEASURED 2026-08-15 over all 42 domains: finance held 18 352 // killed=1 records and published redseen=0 because its stamp 353 // epoch was 100 SECONDS OLDER than the bites it should have 354 // counted; librarian (2s) and surveys (3s) show the identical 355 // ordering. A single re-stamp moved finance 0 -> 16 with no 356 // gate re-run differently and no source changed -- the proof 357 // was on disk the whole time and the stamp could not see it. 358 // A STAMP THAT PREDATES ITS OWN EVIDENCE UNDERSTATES THE 359 // SYSTEM'S HONESTY AND READS EXACTLY LIKE VACUOUS GATES. 360 let rc3: i64 = eb_run2(evelf, dom, 0 as *u8, outp) 361 if rc3 == 0 { w(" RESTAMP "); w(dom); w(" post-sweep -> MEASURED-HONEST\n") } else { w(" RESTAMP "); w(dom); w(" post-sweep RED (exit "); wn(rc3); w(")\n"); failed = failed + 1 } 362 restamped = restamped + 1 363 } else { deferred = deferred + 1; w(" DEFER "); w(dom); w(" sweep (budget spent)\n") } 364 } } 365 } 366 } 367 } 368 } 369 } 370 } 371 if reclen <= 0 { pos = nr } else { pos = pos + reclen } 372 } 373 } 374 } 375 sys_close(fd) 376 377 // swept WAS COUNTED AND NEVER PRINTED, so a pass that swept nothing and a pass that swept every 378 // overdue domain produced IDENTICAL summaries. The non-vacuity half of this beat's work was 379 // invisible in the beat's own log, which is why "scanned=43 refreshed=3 failed=0" read as the 380 // whole story when it was reporting only the cheap half. A COUNTER THAT IS TALLIED BUT NEVER 381 // EMITTED IS A MEASUREMENT THE ORGANISATION IS PAYING FOR AND NOT COLLECTING. 382 w(" scanned="); wn(scanned); w(" refreshed="); wn(refreshed); w(" swept="); wn(swept); w(" restamped="); wn(restamped); w(" deferred="); wn(deferred); w(" failed="); wn(failed); w("\n") 383 if havesw == 0 { w(" NOTE nx_bite_sweep.elf unresolved -- non-vacuity records will not be renewed by this beat\n") } 384 385 let lfd: i64 = sys_openat_wr("knowledge/status/evidence_beat.log\x00" as *u8, 0x1a4) 386 if lfd >= 0 { 387 wf(lfd, "NX-EVIDENCE-BEAT scanned=" as *u8); wnf(lfd, scanned) 388 wf(lfd, " refreshed=" as *u8); wnf(lfd, refreshed) 389 wf(lfd, " deferred=" as *u8); wnf(lfd, deferred) 390 wf(lfd, " failed=" as *u8); wnf(lfd, failed) 391 wf(lfd, " ttl=" as *u8); wnf(lfd, ttl) 392 // ts= is the DEAD-MAN'S-SWITCH marker knowledge/registry/cron_heartbeats.tsv looks for. Emitting 393 // only `epoch=` would leave the watch permanently stale even while the beat ran perfectly -- the 394 // heartbeat would report a dead cadence that is actually alive, which is the same false-negative 395 // class as every other reader/writer dialect mismatch this session. Both are written: ts= for the 396 // watch, epoch= for anything reading this log the way the stamps are read. 397 wf(lfd, " ts=" as *u8); wnf(lfd, now) 398 wf(lfd, " epoch=" as *u8); wnf(lfd, now) 399 wf(lfd, "\n" as *u8) 400 // DEFERRED WORK IS NOT A FAILURE, but it must be VISIBLE: a beat that silently drops its backlog 401 // lets the board age out one domain at a time while every log line still reads GREEN. 402 if failed == 0 { wf(lfd, "VERDICT=GREEN evidence renewed within its half-life\n" as *u8) } else { wf(lfd, "VERDICT=RED a refresh failed -- a domain's evidence could not be re-measured\n" as *u8) } 403 sys_close(lfd) 404 } 405 406 if failed == 0 { w("VERDICT: verdict=GREEN (nothing overdue, or all attempted refreshes succeeded)\n"); sys_exit(0); return 0 } 407 w("VERDICT: verdict=RED (a refresh failed)\n") 408 sys_exit(1) 409 return 1 410}