code wiki / _hdl_build / nx_cron_watch.nx

nx_cron_watch.nx source

↩ module page · 162 lines · 9411 B

1// nx_cron_watch.nx -- CRON/AUTOMATION FRESHNESS SUPERVISOR (operator: "prevent things like this... 2// supervised"; the next silent-failure class after API-contract drift + lib drift = a scheduled job that 3// SILENTLY STOPS FIRING, e.g. seq22 team_pulse died unnoticed). SOTA = the dead-man's-switch / heartbeat 4// model (Healthchecks.io "expected period + grace time", Cronitor, Dead Man's Snitch): a job pings on its 5// schedule; a check-in missed beyond a grace window -> STALE/alert. Sovereign twist: the heartbeat is each 6// job's own evidence-log `ts=<epoch>` (no external SaaS; evidence-layer native). Data-driven (rule 11): 7// knowledge/registry/cron_heartbeats.tsv rows name<TAB>heartbeat-file<TAB>ts-marker<TAB>max-age-secs<TAB>remediation. 8// max-age = expected-interval + grace. age = now - ts. age>max-age -> STALE. missing ts -> STALE (never fired). 9// nx_cron_watch check [manifest] (JSON: per watch fresh/stale + age + verdict GREEN/STALE-DETECTED) 10// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 11import "nx_syscalls.nx" 12 13const CW_CAP: i64 = 262144 14const CW_TAB: i64 = 9 15const CW_NL: i64 = 10 16const CW_HASH: i64 = 35 17const CW_STDERR: i64 = 2 18const CW_SPAN: i64 = 16 19const CW_EXIT_USAGE: i64 = 2 20 21func cw_werr(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(CW_STDERR, s, n); return 0 } 22func cw_vlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 23func cw_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o] = s[i]; o = o + 1; i = i + 1 } return o } 24func cw_catn(d: *u8, o: i64, v: i64) -> i64 { let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { d[o] = 45 as u8; o = o + 1; m = 0 - m } 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 } var i: i64 = 0; while i < k { d[o] = t[k-1-i]; o = o + 1; i = i + 1 } return o } 25func cw_cat_esc(d: *u8, o: i64, q: *u8, s: i64, e: i64) -> i64 { var i: i64 = s; while i < e { var c: i64 = q[i] as i64; if c == 34 { c = 39 } if c == 92 { c = 47 } if c < 32 { c = 32 } d[o] = c as u8; o = o + 1; i = i + 1 } return o } 26// TAIL-READ (2026-08-02, debt 1785708737). This used to read from byte 0 up to `cap`, so once an 27// append-only stamp log grew past CW_CAP the watch only ever saw the HEAD of the file -- and computed 28// "latest" from the OLDEST bytes it could afford. MEASURED: surfsentinel-beat reported last_ts=1784445800 29// (~14.6 DAYS stale) while the log's real tail showed a COMPLETED run 23 minutes earlier. The guard aged 30// BACKWARDS as its subject got healthier, and screamed louder the longer the job ran correctly. 31// A FRESHNESS CHECK MUST READ THE TAIL. Seek to max(0, size-cap) so the newest evidence is always in the 32// window; a file smaller than cap is read whole exactly as before. 33func cw_read(path: *u8, buf: *u8, cap: i64) -> i64 { 34 let fd: i64 = sys_openat_rd(path) 35 if fd < 0 { return 0 - 1 } 36 let size: i64 = sys_lseek(fd, 0, 2) 37 if size > cap { sys_lseek(fd, size - cap, 0) } else { sys_lseek(fd, 0, 0) } 38 var n: i64 = 0 39 var go: i64 = 1 40 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } } 41 sys_close(fd) 42 return n 43} 44// find <marker> substring, then parse the decimal number immediately following it. -1 if not found. 45func cw_num_after(buf: *u8, n: i64, marker: *u8) -> i64 { 46 var ml: i64 = 0 47 while marker[ml] != (0 as u8) { ml = ml + 1 } 48 if ml == 0 { return 0 - 1 } 49 var last: i64 = 0 - 1 50 var found: i64 = 0 51 var i: i64 = 0 52 while i + ml <= n { 53 var j: i64 = 0 54 var ok: i64 = 1 55 while j < ml { if buf[i+j] != marker[j] { ok = 0; j = ml } else { j = j + 1 } } 56 if ok == 1 { 57 var p: i64 = i + ml 58 var v: i64 = 0 59 var got: i64 = 0 60 var go: i64 = 1 61 while go == 1 { if p >= n { go = 0 } else { let c: i64 = buf[p] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); got = 1; p = p + 1 } else { go = 0 } } else { go = 0 } } } 62 // LAST MATCH WINS (2026-08-02, debt 1785708737 -- the twin of the tail-read above). This used to 63 // `return v` on the FIRST marker found, which is correct only for a single-line stamp file 64 // (`date > log`). Every APPEND-only evidence log (`>>`) puts the FRESHEST stamp LAST, so the 65 // first match is the OLDEST run -- the watch then reports a healthy hourly job as weeks stale. 66 // That is why the single-line watches (planeguard/guardcheck) read correctly while the appending 67 // ones (surfsentinel) did not: first==last only when there is one line. 68 if got == 1 { last = v; found = 1 } 69 } 70 i = i + 1 71 } 72 if found == 1 { return last } 73 return 0 - 1 74} 75func cw_le(q: *u8, i: i64, n: i64) -> i64 { var e: i64 = i; var s: i64 = 1; while s == 1 { if e >= n { s = 0 } else { if q[e] == (CW_NL as u8) { s = 0 } else { e = e + 1 } } } return e } 76func cw_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 { 77 var col: i64 = 0 78 var p: i64 = ls 79 while col < c { 80 var s: i64 = 1 81 while s == 1 { if p >= le { return 0 } if q[p] == (CW_TAB as u8) { s = 0 } else { p = p + 1 } } 82 p = p + 1 83 col = col + 1 84 } 85 var e: i64 = p 86 var s2: i64 = 1 87 while s2 == 1 { if e >= le { s2 = 0 } else { if q[e] == (CW_TAB as u8) { s2 = 0 } else { e = e + 1 } } } 88 out[0] = p 89 out[1] = e 90 return 1 91} 92func cw_cstr(q: *u8, s: i64, e: i64, dst: *u8) -> i64 { var i: i64 = 0; while s + i < e { dst[i] = q[s+i]; i = i + 1 } dst[i] = 0 as u8; return i } 93func cw_atoi_span(q: *u8, s: i64, e: i64) -> i64 { var v: i64 = 0; var i: i64 = s; while i < e { let c: i64 = q[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 } return v } 94func main(argc: i64, argv: *i64) -> i64 { 95 // single verb (check); argv[1] optionally overrides the manifest path if it looks like a path 96 var mpath: *u8 = "knowledge/registry/cron_heartbeats.tsv" as *u8 97 if argc > 2 { mpath = argv[2] as *u8 } 98 let man: *u8 = sys_mmap(CW_CAP) 99 let mn: i64 = cw_read(mpath, man, CW_CAP) 100 if mn <= 0 { cw_werr("CW-FAIL manifest empty or unreadable\n" as *u8); sys_exit(1); return 1 } 101 let now: i64 = sys_now_realtime_sec() 102 let fbuf: *u8 = sys_mmap(CW_CAP) 103 let fpath: *u8 = sys_mmap(512) 104 let tmark: *u8 = sys_mmap(64) 105 let c0: *i64 = sys_mmap(CW_SPAN) as *i64 106 let c1: *i64 = sys_mmap(CW_SPAN) as *i64 107 let c2: *i64 = sys_mmap(CW_SPAN) as *i64 108 let c3: *i64 = sys_mmap(CW_SPAN) as *i64 109 let c4: *i64 = sys_mmap(CW_SPAN) as *i64 110 let out: *u8 = sys_mmap(CW_CAP) 111 var o: i64 = 0 112 o = cw_cat(out, o, "{\"verb\":\"check\",\"epoch\":" as *u8) 113 o = cw_catn(out, o, now) 114 o = cw_cat(out, o, ",\"watches\":[" as *u8) 115 var total: i64 = 0 116 var stale: i64 = 0 117 var emitted: i64 = 0 118 var i: i64 = 0 119 while i < mn { 120 let le: i64 = cw_le(man, i, mn) 121 if le > i { if (man[i] as i64) != CW_HASH { 122 if cw_col(man, i, le, 0, c0) == 1 { if cw_col(man, i, le, 1, c1) == 1 { if cw_col(man, i, le, 2, c2) == 1 { if cw_col(man, i, le, 3, c3) == 1 { 123 cw_cstr(man, c1[0], c1[1], fpath) 124 cw_cstr(man, c2[0], c2[1], tmark) 125 let maxage: i64 = cw_atoi_span(man, c3[0], c3[1]) 126 total = total + 1 127 let fn: i64 = cw_read(fpath, fbuf, CW_CAP) 128 var ts: i64 = 0 - 1 129 if fn > 0 { ts = cw_num_after(fbuf, fn, tmark) } 130 var age: i64 = 0 - 1 131 var fresh: i64 = 0 132 if ts >= 0 { age = now - ts; if age < 0 { age = 0 } if age <= maxage { fresh = 1 } } 133 if fresh == 0 { stale = stale + 1 } 134 if emitted > 0 { o = cw_cat(out, o, "," as *u8) } 135 o = cw_cat(out, o, "{\"name\":\"" as *u8) 136 o = cw_cat_esc(out, o, man, c0[0], c0[1]) 137 o = cw_cat(out, o, "\",\"last_ts\":" as *u8) 138 o = cw_catn(out, o, ts) 139 o = cw_cat(out, o, ",\"age_secs\":" as *u8) 140 o = cw_catn(out, o, age) 141 o = cw_cat(out, o, ",\"max_age\":" as *u8) 142 o = cw_catn(out, o, maxage) 143 o = cw_cat(out, o, ",\"fresh\":" as *u8) 144 o = cw_catn(out, o, fresh) 145 if fresh == 0 { if cw_col(man, i, le, 4, c4) == 1 { o = cw_cat(out, o, ",\"remediation\":\"" as *u8); o = cw_cat_esc(out, o, man, c4[0], c4[1]); o = cw_cat(out, o, "\"" as *u8) } } 146 o = cw_cat(out, o, "}" as *u8) 147 emitted = emitted + 1 148 } } } } 149 } } 150 i = le + 1 151 } 152 o = cw_cat(out, o, "],\"total\":" as *u8) 153 o = cw_catn(out, o, total) 154 o = cw_cat(out, o, ",\"stale\":" as *u8) 155 o = cw_catn(out, o, stale) 156 o = cw_cat(out, o, ",\"verdict\":\"" as *u8) 157 if stale == 0 { o = cw_cat(out, o, "GREEN" as *u8) } else { o = cw_cat(out, o, "STALE-DETECTED" as *u8) } 158 o = cw_cat(out, o, "\",\"envelope\":\"manifest + each heartbeat/stamp file read bounded per CW_CAP; a job whose evidence exceeds the cap reads TRUNCATED and could be misjudged stale/fresh -- declared per the scale-law (F846), never silent\"}\n" as *u8) 159 sys_write(1, out, o) 160 sys_exit(0) 161 return 0 162}