code wiki / (root) / nx_gate_green.nx

nx_gate_green.nx source

↩ module page · 100 lines · 4175 B

1// nx_gate_green.nx -- shared LAST-VERDICT-LINE judging (the Examiner pattern 2// as a reusable lib): "the LAST line containing <anchor> must contain <pat>". 3// 4// module: nishi-core.status.gate_green 5// capability: CORE_COMPUTE 6// 7// EXTRACTED 2026-06-10 during the standards audit of nx_sreach_scorecard, 8// which had a REAL false-green bug: its line-bounding loop discarded the 9// newline index, so the pattern window ran to END OF FILE -- a "rc=0" on a 10// LATER line could green a rung whose own line said rc=1. Fixed here with the 11// found-index pattern and pinned by nx_gate_green_test KATs (the false-green 12// construction is KAT 3). Anything judging gate logs should use THIS, not a 13// private copy. 14 15import "nx_str.nx" 16import "nx_syscalls.nx" 17 18const GG_FILE_CAP: i64 = 524288 19 20// ---- TRI-STATE JUDGMENT (seq585, 2026-07-23). The 2-valued judge below could not tell 21// "this gate FAILED" from "this gate emitted no verdict I can read" -- both were 0 -- so 953 22// runnable, genuinely PASSING gates were machine-read as NOT-GREEN: a silent false negative 23// across the whole fleet, and the reason nx_gate_migrate had to hand-roll its own absence 24// check. ABSENT IS NOW A NAMED STATE. The 1/0 wrappers keep their exact contract by clamping 25// (rule 19), so all 14 live call sites stay byte-identical -- including the comms censuses 26// that legitimately read ==0 as "a missing log is not green". 27const GG_GREEN: i64 = 1 28const GG_RED: i64 = 0 29const GG_UNJUDGEABLE: i64 = 0 - 1 // anchor absent: the log says NOTHING about a verdict 30const GG_UNREADABLE: i64 = 0 - 2 // no such file / empty: nothing to judge at all 31const GG_LF: i64 = 0x0A 32 33func gg_read(path: *u8, buf: *u8, cap: i64) -> i64 { 34 let fd: i64 = sys_openat_rd(path) 35 if fd < 0 { return 0 } 36 var total: i64 = 0 37 var go: i64 = 1 38 while go == 1 { 39 let n: i64 = sys_read(fd, (((buf as i64) + total) as *u8), cap - total) 40 if n <= 0 { go = 0 } 41 if n > 0 { total = total + n; if total >= cap { go = 0 } } 42 } 43 sys_close(fd) 44 return total 45} 46 47// last index of needle in buf[0..n) or -1 48func gg_last(buf: *u8, n: i64, needle: *u8) -> i64 { 49 let nn: i64 = nx_str_len(needle) 50 if nn == 0 { return 0 - 1 } 51 var found: i64 = 0 - 1 52 var i: i64 = 0 53 while i + nn <= n { 54 var j: i64 = 0 55 var ok: i64 = 1 56 while j < nn { 57 if buf[i + j] != needle[j] { ok = 0; j = nn } else { j = j + 1 } 58 } 59 if ok == 1 { found = i } 60 i = i + 1 61 } 62 return found 63} 64 65// GREEN / RED / UNJUDGEABLE for the LAST line containing `anchor` in buf[0..n). 66// The window is THAT LINE ONLY: [anchor_pos, newline) -- never the file tail. 67func gg_line_judge(buf: *u8, n: i64, anchor: *u8, pat: *u8) -> i64 { 68 let at: i64 = gg_last(buf, n, anchor) 69 if at < 0 { return GG_UNJUDGEABLE } 70 var nl: i64 = n // no trailing newline -> line ends at EOF 71 var s: i64 = at 72 while s < n { if (buf[s] as i64) == GG_LF { nl = s; s = n } else { s = s + 1 } } 73 let wn: i64 = nl - at 74 if wn <= 0 { return GG_RED } 75 if gg_last((((buf as i64) + at) as *u8), wn, pat) >= 0 { return GG_GREEN } 76 return GG_RED 77} 78 79// 1 iff the LAST line containing `anchor` in buf[0..n) also contains `pat`. 80// UNCHANGED CONTRACT: every non-green state clamps to 0. A caller that must tell 81// "failed" from "did not say" calls gg_line_judge instead. 82func gg_line_green(buf: *u8, n: i64, anchor: *u8, pat: *u8) -> i64 { 83 if gg_line_judge(buf, n, anchor, pat) == GG_GREEN { return 1 } 84 return 0 85} 86 87// file wrapper, tri-state: adds UNREADABLE (absent/empty file) as its own named state, 88// distinct from "file present but silent" (UNJUDGEABLE) and from a real RED. 89func gg_gate_judge(path: *u8, anchor: *u8, pat: *u8) -> i64 { 90 let buf: *u8 = sys_mmap(GG_FILE_CAP) 91 let n: i64 = gg_read(path, buf, GG_FILE_CAP) 92 if n <= 0 { return GG_UNREADABLE } 93 return gg_line_judge(buf, n, anchor, pat) 94} 95 96// file wrapper: read + judge. UNCHANGED CONTRACT (1 green, 0 otherwise). 97func gg_gate_green(path: *u8, anchor: *u8, pat: *u8) -> i64 { 98 if gg_gate_judge(path, anchor, pat) == GG_GREEN { return 1 } 99 return 0 100}