nx_diag_voice_gate.nx source
↩ module page · 272 lines · 15899 B
1// nx_diag_voice_gate.nx -- LN27 (lang.plan, 2026-09-02): EVERY DIAGNOSTIC TEACHES IN ONE VOICE.
2// The operator named the first LN24 messages as output that does not help a programmer grow: a
3// location and a fact, no why, no fix. The parser's teaching sites already carry the shape (nx_diag_at,
4// nx_diag_caret, then "why the build stopped:" and "fix:"); this gate walks EVERY diagnostic emission
5// site in the toolchain sources and refuses a BARE site -- a location or a refusal printed without a
6// why line and a fix line within its window -- as a RATCHET: the bare count per file may never RISE
7// above knowledge/status/diag_voice_ratchet.conf, it self-tightens on every fall, and it never rewrites
8// its baseline on a rise (a ratchet that launders itself green is a threshold wearing a ratchet's name).
9// It prints the worklist (BARE file:line) so the count is actionable, never a bare number.
10//
11// SITE RULE (mechanical, declared, bite-proven below): a source line is an emission site when it is
12// not a comment line and, before any `//`, contains one of
13// nx_diag_at( nx_diag_organ_at( "error: nxcx_log("nx_compile_x86: "nxasm: FATAL "error at function
14// and is not a `func ` definition line. It is VOICED when, within the next DV_WINDOW lines and before
15// the next site, one line carries a why ("why the build stopped" or a call to nx_diag_why_) and one
16// carries a fix ("fix:" or a did-you-mean nx_dym_note). Everything else is BARE.
17// The classifier is a pure function over a buffer so the fixtures below are assembled at RUNTIME --
18// a detector that scans source would otherwise find its own test fixture in this very file.
19//
20// nx_diag_voice_gate -- census + ratchet + controls, verdict in the exit code (gv_verdict)
21// license_tier: ORIGINAL layer: lang module: nishi-core.lang.diag_voice_gate
22import "nx_syscalls.nx"
23import "nx_gate_verdict.nx"
24
25const DV_WINDOW: i64 = 60 // lines after a site in which why and fix must appear (the exhaustiveness site lists every missing variant first: 48 lines)
26const DV_LINECAP: i64 = 4096 // longest source line examined (longer lines are cut, never skipped)
27const DV_NFILES: i64 = 8
28const DV_PATHCAP: i64 = 256
29const DV_CONFCAP: i64 = 4096
30const DV_RATCHET: *u8 = "knowledge/status/diag_voice_ratchet.conf\x00" as *u8
31
32func dv_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
33func dv_w(s: *u8) -> i64 { sys_write(1, s, dv_slen(s)); return 0 }
34func dv_n(v: i64) -> i64 {
35 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 }
36 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
37 let t: *u8 = sys_mmap(24); var k: i64 = 0
38 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
39 let o: *u8 = sys_mmap(24); var w: i64 = 0; var q: i64 = k - 1
40 while q >= 0 { o[w] = t[q]; w = w + 1; q = q - 1 }
41 sys_write(1, o, w); return 0
42}
43func dv_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } dst[o] = 0 as u8; return o }
44
45// first index of pat in line[0..n), or -1.
46func dv_find(line: *u8, n: i64, pat: *u8) -> i64 {
47 let pl: i64 = dv_slen(pat)
48 if pl <= 0 { return 0 - 1 }
49 var i: i64 = 0
50 while i + pl <= n {
51 var j: i64 = 0; var ok: i64 = 1
52 while j < pl { if line[i + j] != pat[j] { ok = 0; j = pl } else { j = j + 1 } }
53 if ok == 1 { return i }
54 i = i + 1
55 }
56 return 0 - 1
57}
58// index of the first non-space byte.
59func dv_lead(line: *u8, n: i64) -> i64 {
60 var i: i64 = 0
61 while i < n { if line[i] == (32 as u8) { i = i + 1 } else { if line[i] == (9 as u8) { i = i + 1 } else { return i } } }
62 return n
63}
64// a pattern counts only when it sits BEFORE any line comment.
65func dv_has_code(line: *u8, n: i64, pat: *u8) -> i64 {
66 let p: i64 = dv_find(line, n, pat)
67 if p < 0 { return 0 }
68 let c: i64 = dv_find(line, n, "//" as *u8)
69 if c >= 0 { if c < p { return 0 } }
70 return 1
71}
72func dv_is_site(line: *u8, n: i64) -> i64 {
73 let l: i64 = dv_lead(line, n)
74 if l + 1 < n { if line[l] == (47 as u8) { if line[l + 1] == (47 as u8) { return 0 } } } // comment line
75 if dv_find(line, n, "func " as *u8) == l { return 0 } // a definition, not a site
76 if dv_has_code(line, n, "nx_diag_at(" as *u8) == 1 { return 1 }
77 if dv_has_code(line, n, "nx_diag_organ_at(" as *u8) == 1 { return 1 }
78 if dv_has_code(line, n, "\"error: " as *u8) == 1 { return 1 }
79 if dv_has_code(line, n, "nxcx_log(\"nx_compile_x86: " as *u8) == 1 { return 1 }
80 if dv_has_code(line, n, "\"nxasm: FATAL" as *u8) == 1 { return 1 }
81 if dv_has_code(line, n, "\"error at function" as *u8) == 1 { return 1 }
82 return 0
83}
84func dv_is_why(line: *u8, n: i64) -> i64 {
85 if dv_find(line, n, "why the build stopped" as *u8) >= 0 { return 1 }
86 if dv_find(line, n, "why this matters" as *u8) >= 0 { return 1 } // the non-fatal form: a warning still teaches
87 if dv_has_code(line, n, "nx_diag_why_" as *u8) == 1 { return 1 }
88 return 0
89}
90func dv_is_fix(line: *u8, n: i64) -> i64 {
91 if dv_find(line, n, "fix:" as *u8) >= 0 { return 1 }
92 if dv_has_code(line, n, "nx_dym_note" as *u8) == 1 { return 1 }
93 return 0
94}
95
96// THE CENSUS over one buffer. out[0]=sites out[1]=bare out[2]=voiced. list=1 prints BARE <fname>:<line>.
97// Lines are indexed into ls[] once, then every site looks ahead through the window.
98func dv_census(buf: *u8, n: i64, fname: *u8, out: *i64, list: i64) -> i64 {
99 var nl: i64 = 1; var i: i64 = 0
100 while i < n { if buf[i] == (10 as u8) { nl = nl + 1 } i = i + 1 }
101 let ls: *i64 = sys_mmap((nl + 2) * 8) as *i64
102 let ll: *i64 = sys_mmap((nl + 2) * 8) as *i64
103 var cnt: i64 = 0; var st: i64 = 0; i = 0
104 while i <= n {
105 var eol: i64 = 0
106 if i == n { eol = 1 } else { if buf[i] == (10 as u8) { eol = 1 } }
107 if eol == 1 { ls[cnt] = st; var w: i64 = i - st; if w > DV_LINECAP { w = DV_LINECAP } ll[cnt] = w; cnt = cnt + 1; st = i + 1 }
108 i = i + 1
109 }
110 let issite: *i64 = sys_mmap((cnt + 2) * 8) as *i64
111 var k: i64 = 0
112 while k < cnt { issite[k] = dv_is_site((buf as i64 + ls[k]) as *u8, ll[k]); k = k + 1 }
113 var sites: i64 = 0; var bare: i64 = 0; var voiced: i64 = 0
114 k = 0
115 while k < cnt {
116 if issite[k] == 1 {
117 sites = sites + 1
118 var why: i64 = 0; var fix: i64 = 0
119 var j: i64 = k + 1; var go: i64 = 1
120 while go == 1 {
121 if j >= cnt { go = 0 } else {
122 if j - k > DV_WINDOW { go = 0 } else {
123 if issite[j] == 1 { go = 0 } else {
124 let lp: *u8 = (buf as i64 + ls[j]) as *u8
125 if dv_is_why(lp, ll[j]) == 1 { why = 1 }
126 if dv_is_fix(lp, ll[j]) == 1 { fix = 1 }
127 j = j + 1
128 }
129 }
130 }
131 }
132 if (why == 1) & (fix == 1) { voiced = voiced + 1 } else {
133 bare = bare + 1
134 if list == 1 { dv_w(" BARE " as *u8); dv_w(fname); dv_w(":" as *u8); dv_n(k + 1); if why == 0 { dv_w(" no-why" as *u8) } if fix == 0 { dv_w(" no-fix" as *u8) } dv_w("\n" as *u8) }
135 }
136 }
137 k = k + 1
138 }
139 out[0] = sites; out[1] = bare; out[2] = voiced
140 return sites
141}
142
143// read <root>/<fname> with a two-root probe: buildroot/runtime/ (NAS gate CWD) then runtime/ (laptop CWD).
144func dv_read_src(fname: *u8, lenp: *i64) -> *u8 {
145 let p: *u8 = sys_mmap(DV_PATHCAP)
146 var o: i64 = dv_cat(p, 0, "buildroot/runtime/" as *u8); o = dv_cat(p, o, fname)
147 lenp[0] = 0
148 var b: *u8 = sys_read_file(p, lenp)
149 if lenp[0] > 0 { return b }
150 o = dv_cat(p, 0, "runtime/" as *u8); o = dv_cat(p, o, fname)
151 lenp[0] = 0
152 b = sys_read_file(p, lenp)
153 return b
154}
155// baseline row "<fname>=<n>" -> n, or -1 when absent.
156func dv_baseline(conf: *u8, cn: i64, fname: *u8) -> i64 {
157 if cn <= 0 { return 0 - 1 }
158 let key: *u8 = sys_mmap(DV_PATHCAP)
159 var o: i64 = dv_cat(key, 0, fname); o = dv_cat(key, o, "=" as *u8)
160 let p: i64 = dv_find(conf, cn, key)
161 if p < 0 { return 0 - 1 }
162 var i: i64 = p + o; var v: i64 = 0; var any: i64 = 0
163 while i < cn { let c: i64 = conf[i] as i64; if (c >= 48) & (c <= 57) { v = v * 10 + (c - 48); any = 1; i = i + 1 } else { i = cn } }
164 if any == 0 { return 0 - 1 }
165 return v
166}
167func dv_write_conf(names: *i64, bares: *i64, nf: i64) -> i64 {
168 let b: *u8 = sys_mmap(DV_CONFCAP)
169 var o: i64 = dv_cat(b, 0, "# diag_voice_ratchet.conf -- BARE diagnostic sites per toolchain source (LN27). Written by nx_diag_voice_gate on every FALL; a RISE is RED and never rewrites this file.\n" as *u8)
170 var i: i64 = 0
171 while i < nf {
172 o = dv_cat(b, o, names[i] as *u8); o = dv_cat(b, o, "=" as *u8)
173 let t: *u8 = sys_mmap(24); var m: i64 = bares[i]; var k: i64 = 0
174 if m == 0 { t[0] = 48 as u8; k = 1 }
175 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
176 var q: i64 = k - 1
177 while q >= 0 { b[o] = t[q]; o = o + 1; q = q - 1 }
178 b[o] = 10 as u8; o = o + 1; b[o] = 0 as u8
179 i = i + 1
180 }
181 let fd: i64 = sys_openat_wr(DV_RATCHET, 420)
182 if fd < 0 { return 0 - 1 }
183 sys_write(fd, b, o); sys_close(fd)
184 return o
185}
186
187// THE SYMBOL THE lang.matrix WATCH MEASURES (diag_voice_gate): the whole census + ratchet as one call.
188// Returns the total BARE count over the toolchain, or -1 when a source could not be read.
189func diag_voice_gate(c: *i64) -> i64 {
190 let names: *i64 = sys_mmap(DV_NFILES * 8) as *i64
191 names[0] = "nx_tokenizer.nx" as *u8 as i64; names[1] = "nx_parse.nx" as *u8 as i64
192 names[2] = "nx_ir.nx" as *u8 as i64; names[3] = "nx_compile_x86.nx" as *u8 as i64
193 names[4] = "nxasm_x86_main.nx" as *u8 as i64; names[5] = "nx_x86_64_ctx.nx" as *u8 as i64
194 names[6] = "nx_opt.nx" as *u8 as i64; names[7] = "nx_x86_regalloc.nx" as *u8 as i64
195 let bares: *i64 = sys_mmap(DV_NFILES * 8) as *i64
196 let lenp: *i64 = sys_mmap(16) as *i64
197 let out: *i64 = sys_mmap(32) as *i64
198 let cl: *i64 = sys_mmap(16) as *i64
199 cl[0] = 0
200 let conf: *u8 = sys_read_file(DV_RATCHET, cl)
201 var readok: i64 = 0; var sites: i64 = 0; var bare: i64 = 0; var voiced: i64 = 0
202 var rises: i64 = 0; var falls: i64 = 0; var firsts: i64 = 0
203 var i: i64 = 0
204 while i < DV_NFILES {
205 let fname: *u8 = names[i] as *u8
206 let b: *u8 = dv_read_src(fname, lenp)
207 if lenp[0] > 0 {
208 readok = readok + 1
209 dv_census(b, lenp[0], fname, out, 1)
210 sites = sites + out[0]; bare = bare + out[1]; voiced = voiced + out[2]
211 bares[i] = out[1]
212 let base: i64 = dv_baseline(conf, cl[0], fname)
213 dv_w(" FILE " as *u8); dv_w(fname); dv_w(" sites=" as *u8); dv_n(out[0]); dv_w(" voiced=" as *u8); dv_n(out[2]); dv_w(" bare=" as *u8); dv_n(out[1]); dv_w(" baseline=" as *u8); dv_n(base)
214 if base < 0 { firsts = firsts + 1; dv_w(" FIRST-SIGHT" as *u8) } else {
215 if out[1] > base { rises = rises + 1; dv_w(" RISE" as *u8) }
216 if out[1] < base { falls = falls + 1; dv_w(" FALL" as *u8) }
217 }
218 dv_w("\n" as *u8)
219 } else { bares[i] = 0 - 1; dv_w(" FILE " as *u8); dv_w(fname); dv_w(" UNREADABLE\n" as *u8) }
220 i = i + 1
221 }
222 dv_w("DIAG-VOICE files=" as *u8); dv_n(readok); dv_w("/" as *u8); dv_n(DV_NFILES); dv_w(" sites=" as *u8); dv_n(sites); dv_w(" voiced=" as *u8); dv_n(voiced); dv_w(" bare=" as *u8); dv_n(bare)
223 dv_w(" rises=" as *u8); dv_n(rises); dv_w(" falls=" as *u8); dv_n(falls); dv_w(" first_sight=" as *u8); dv_n(firsts); dv_w(" (voiced+bare=sites per file; a BARE row above names the site)\n" as *u8)
224 gv_check("toolchain-sources-all-readable" as *u8, readok == DV_NFILES, c)
225 gv_check("emission-sites-found-not-vacuous" as *u8, sites > 0, c)
226 gv_check("positive-control-existing-teaching-sites-are-voiced" as *u8, voiced > 0, c)
227 gv_check("partition-voiced-plus-bare-equals-sites" as *u8, voiced + bare == sites, c)
228 gv_check("ratchet-no-file-rises-above-its-baseline" as *u8, rises == 0, c)
229 // TIGHTEN on a fall or a first sight; NEVER on a rise (a rise stays RED against the old baseline).
230 var wrote: i64 = 0
231 if rises == 0 { if (falls > 0) | (firsts > 0) { wrote = dv_write_conf(names, bares, DV_NFILES) } }
232 if wrote > 0 {
233 let cl2: *i64 = sys_mmap(16) as *i64; cl2[0] = 0
234 let conf2: *u8 = sys_read_file(DV_RATCHET, cl2)
235 var agree: i64 = 1; i = 0
236 while i < DV_NFILES { if dv_baseline(conf2, cl2[0], names[i] as *u8) != bares[i] { agree = 0 } i = i + 1 }
237 gv_check("ratchet-tightened-and-reread-matches-by-content" as *u8, agree == 1, c)
238 dv_w(" RATCHET written " as *u8); dv_w(DV_RATCHET); dv_w(" bytes=" as *u8); dv_n(wrote); dv_w("\n" as *u8)
239 }
240 if readok < DV_NFILES { return 0 - 1 }
241 return bare
242}
243
244func main() -> i64 {
245 let c: *i64 = gv_ctr()
246 // ---- NEGATIVE / POSITIVE CONTROLS on runtime-assembled fixtures (never files the census scans) ----
247 let out: *i64 = sys_mmap(32) as *i64
248 let fx: *u8 = sys_mmap(4096)
249 var o: i64 = dv_cat(fx, 0, "func f(P: *Parser) -> i64 {\n nx_diag_at(t.line)\n nx_diag_puts(\": this name is used before it is declared\\n\" as *u8)\n return 1\n}\n" as *u8)
250 dv_census(fx, o, "fx_bare" as *u8, out, 0)
251 gv_check("neg-control-planted-bare-site-reads-BARE" as *u8, (out[0] == 1) & (out[1] == 1), c)
252 o = dv_cat(fx, 0, "func f(P: *Parser) -> i64 {\n nx_diag_at(t.line)\n nx_diag_puts(\": this name is used before it is declared\\n\" as *u8)\n nx_diag_puts(\" why the build stopped: a use before a declaration has nothing to bind to\\n\" as *u8)\n nx_diag_puts(\" fix: move the declaration above this line\\n\" as *u8)\n return 1\n}\n" as *u8)
253 dv_census(fx, o, "fx_voiced" as *u8, out, 0)
254 gv_check("control-voiced-site-reads-VOICED" as *u8, (out[0] == 1) & (out[2] == 1) & (out[1] == 0), c)
255 o = dv_cat(fx, 0, "func f() -> i64 {\n // the parser calls nx_diag_at( here in prose only\n let x: i64 = 1 // nx_diag_organ_at( in a trailing comment\n return x\n}\n" as *u8)
256 dv_census(fx, o, "fx_comment" as *u8, out, 0)
257 gv_check("control-comment-mentions-are-not-sites" as *u8, out[0] == 0, c)
258 o = dv_cat(fx, 0, "func nx_diag_at(line: i64) -> i64 {\n nx_diag_puts(\"error at \" as *u8)\n return nx_diag_loc(line)\n}\n" as *u8)
259 dv_census(fx, o, "fx_def" as *u8, out, 0)
260 gv_check("control-the-voice-helper-definition-is-not-a-site" as *u8, out[0] == 0, c)
261 o = dv_cat(fx, 0, "func g() -> i64 {\n nx_diag_at(t.line)\n nx_diag_puts(\": x\\n\" as *u8)\n nx_diag_why_undefined()\n nx_dym_note2(P, nm, nl)\n return 1\n}\n" as *u8)
262 dv_census(fx, o, "fx_helpers" as *u8, out, 0)
263 gv_check("control-why-and-fix-helpers-count-as-voice" as *u8, (out[0] == 1) & (out[2] == 1), c)
264 o = dv_cat(fx, 0, "func h() -> i64 {\n nx_diag_at(t.line)\n nx_diag_puts(\" why the build stopped: only why, no fix\\n\" as *u8)\n nx_diag_at(u.line)\n nx_diag_puts(\" fix: the fix belongs to the SECOND site, not the first\\n\" as *u8)\n return 1\n}\n" as *u8)
265 dv_census(fx, o, "fx_window" as *u8, out, 0)
266 gv_check("neg-control-a-fix-after-the-next-site-does-not-voice-the-first" as *u8, (out[0] == 2) & (out[1] == 2), c)
267
268 // ---- THE CENSUS over the toolchain sources ----
269 let bare: i64 = diag_voice_gate(c)
270 gv_check("census-ran-over-the-toolchain" as *u8, bare >= 0, c)
271 return gv_verdict("DIAG-VOICE-GATE" as *u8, c, "LN27: every diagnostic emission site in the toolchain carries where, why and fix -- bare sites ratchet down, never up" as *u8)
272}