code wiki / _hdl_build / nx_srclint.nx
nx_srclint.nx source
↩ module page · 761 lines · 40604 B
1// nx_srclint.nx -- LINT THE HAZARDS THAT HAVE ACTUALLY BITTEN, ESTATE-WIDE.
2//
3// RULE 1: CURSOR-SENTINEL. The idiom
4//
5// while p < n { if <done> { p = n + 9 } ... }
6// if p > n { p = p - 9 }
7//
8// writes the loop's EXIT MARKER INTO THE VERY VARIABLE BEING SEARCHED FOR, and the restore lands on
9// `n`, not on the position found. It does not crash and it does not fail to compile -- it silently
10// returns the wrong index, so the caller reads the wrong byte and every downstream number is plausible
11// and wrong. Measured cost on 2026-08-07 alone: FIVE defects.
12//
13// nx_memdemote -- the whole file parsed as ONE line
14// nx_memnew -- file_path extraction returned nothing, the hook silently never fired
15// nx_memnew -- the memfind output parsed as one line, zero results shown
16// nx_unwired -- every identifier ran to end-of-file: 0 functions found across 7,113 sources
17// nx_gatesubj -- the char after an identifier read from the wrong place: 0 of 157 end-to-end
18// gates detected, in the organ built to measure exactly that
19//
20// The fourth and fifth happened INSIDE tools written to catch unverified work, hours after the
21// primitive that fixes it (`gk_eol`) already existed.
22// ★★★★★★ THE FIFTH TIME YOU FIX A BUG BY HAND IS PROOF THE FIX BELONGS IN A LINTER, NOT IN ANOTHER
23// PATCH -- A HAZARD YOU CAN RECOGNISE ON SIGHT IS A HAZARD A MACHINE CAN RECOGNISE EVERY TIME.
24//
25// THE RULE IS THE PAIRING, NOT THE CONSTANT. `x = n + 9` alone is ordinary arithmetic; what makes it
26// this defect is a matching `x - 9` restoring the same variable shortly after. Matching the pair keeps
27// the rule precise -- a linter with false positives is worse than none, because it teaches everyone to
28// ignore it.
29// ★★★★★ A DETECTOR WITH FALSE POSITIVES IS WORSE THAN NONE.
30//
31// usage: nx_srclint [--dir D] [--quiet] [--accept]
32// exit: 0 = no NEW hits since the baseline; 1 = a new hit (named, so it can be attributed)
33// license_tier: ORIGINAL
34import "nx_memplane_lib.nx"
35import "nx_gatekit_lib.nx"
36const SL_MAGIC_8192: i64 = 8192
37const SL_MAGIC_4096: i64 = 4096
38const SL_MAGIC_262144: i64 = 262144
39const SL_MAGIC_262000: i64 = 262000
40
41const SL_DIR: *u8 = "/mnt/c/Users/elder/nishi-core/nxc2/runtime/_hdl_build"
42const SL_MAXF: i64 = 32768 // corpus is 18,561; 16,384 would REFUSE
43const SL_FBUF: i64 = 4194304
44const SL_WIN: i64 = 600 // how far after the `+ N` the paired `- N` may appear
45// SL_BASE is now HOST-RESOLVED at runtime via gk_ops_path (see main); a hardcoded baseline path
46// makes an organ shipped elsewhere ratchet against another machine's record.
47
48func sl_isid(c: i64) -> i64 {
49 if c >= 97 { if c <= 122 { return 1 } }
50 if c >= 65 { if c <= 90 { return 1 } }
51 if c >= 48 { if c <= 57 { return 1 } }
52 if c == 95 { return 1 }
53 return 0
54}
55
56
57
58
59
60// is buf[p..] the literal `lit`?
61func sl_at(buf: *u8, p: i64, n: i64, lit: *u8) -> i64 {
62 let l: i64 = mp_len(lit)
63 if p + l > n { return 0 }
64 var i: i64 = 0
65 while i < l { if buf[p + i] != lit[i] { return 0 } i = i + 1 }
66 return 1
67}
68
69// Read the identifier that ENDS at p-1 (skipping spaces) into out. Returns its length.
70// ⚠ The first version of this rule matched `+ N` ... `- N` anywhere within a window and ignored WHICH
71// VARIABLE was involved. It fired on `nx_analyst_data.nx: + 3 paired with - 3` and dozens more --
72// ordinary arithmetic, not the defect. ★★★★★ A DETECTOR WITH FALSE POSITIVES IS WORSE THAN NONE, AND
73// THE FIRST VERSION OF THIS LINTER WAS ONE. The discriminator is IDENTITY: the idiom is
74// `X = Y + N` restored by `X = X - N`, the SAME X on both sides.
75func sl_lhs(buf: *u8, p: i64, out: *u8) -> i64 {
76 var e: i64 = p - 1
77 var fin: i64 = 0
78 while fin == 0 {
79 if e < 0 { fin = 1 }
80 if fin == 0 { if buf[e] == (32 as u8) { e = e - 1 } else { fin = 1 } }
81 }
82 if e < 0 { out[0] = 0 as u8; return 0 }
83 if sl_isid(buf[e] as i64) == 0 { out[0] = 0 as u8; return 0 }
84 var s: i64 = e
85 var f2: i64 = 0
86 while f2 == 0 {
87 if s <= 0 { f2 = 1 }
88 if f2 == 0 { if sl_isid(buf[s - 1] as i64) == 1 { s = s - 1 } else { f2 = 1 } }
89 }
90 var k: i64 = 0
91 var q: i64 = s
92 while q <= e { if k < 120 { out[k] = buf[q]; k = k + 1 } q = q + 1 }
93 out[k] = 0 as u8
94 return k
95}
96
97// is the line that contains offset i a `//` comment line? (the header of this organ prints the idioms it hunts)
98func sl_line_is_comment(fbuf: *u8, i: i64, n: i64) -> i64 {
99 var bl: i64 = i
100 var fb: i64 = 0
101 while fb == 0 {
102 if bl <= 0 { fb = 1 }
103 if fb == 0 { if fbuf[bl - 1] == (10 as u8) { fb = 1 } else { bl = bl - 1 } }
104 }
105 var sp: i64 = bl
106 var fsp: i64 = 0
107 while fsp == 0 {
108 if sp >= i { fsp = 1 }
109 if fsp == 0 { if fbuf[sp] == (32 as u8) { sp = sp + 1 } else { fsp = 1 } }
110 }
111 if sp + 1 < n { if fbuf[sp] == (47 as u8) { if fbuf[sp + 1] == (47 as u8) { return 1 } } }
112 return 0
113}
114
115// RULE 2: LITERAL-EXIT SENTINEL IN AN INDEXED-CONDITION LOOP (2026-09-02).
116//
117// while KEY[k] != (0 as u8) { ... k = 99 ... }
118//
119// The loop's CONDITION reads through the cursor and the body exits by writing a bare literal into that cursor.
120// Whether the loop ends is then decided by KEY[99] -- whatever rodata sits past the literal -- not by the author.
121// Measured cost: the fleet supervisor (nx_daemon_supervisor ds_life_cycles) spun at 100 percent CPU before its
122// first probe on every generation for a day, once a 1.2 KB conf made every position mismatch; nx_execsurface
123// carried the identical shape and had not fired only because the byte after ITS literal happened to be zero.
124// PRECISION, measured on the tree the day the rule was written: the condition must subscript by a PURE identifier
125// (`X[k]`, not `X[i * 64 + k]`) followed by `!=` or `==`; the assignment must be `<cursor> = <literal>=2` inside
126// the loop's own braces. `while m < 17 { m = 99 }` (a numeric bound in the condition) and `k = 0` resets are NOT
127// this defect and are not flagged. Every exit below is a flag or a return -- this rule does not commit rule 1.
128// Returns the offset of the offending assignment, or -1; cur receives the cursor name, outval[0] the literal.
129func sl_rule2(fbuf: *u8, n: i64, cur: *u8, outval: *i64) -> i64 {
130 var i: i64 = 0
131 while i < n {
132 if sl_at(fbuf, i, n, "while " as *u8) == 1 { if sl_line_is_comment(fbuf, i, n) == 0 {
133 var c: i64 = i + 6
134 var ob: i64 = 0 - 1
135 var brace: i64 = 0 - 1
136 var fc: i64 = 0
137 while fc == 0 {
138 if c >= n { fc = 1 }
139 if fc == 0 { if fbuf[c] == (10 as u8) { fc = 1 } }
140 if fc == 0 { if fbuf[c] == (123 as u8) { brace = c; fc = 1 } }
141 if fc == 0 { if fbuf[c] == (91 as u8) { if ob < 0 { ob = c } } }
142 if fc == 0 { c = c + 1 }
143 }
144 if brace > 0 { if ob > 0 {
145 var k: i64 = 0
146 var q: i64 = ob + 1
147 var okid: i64 = 1
148 var closed: i64 = 0
149 var fq: i64 = 0
150 while fq == 0 {
151 if q >= brace { fq = 1 }
152 if fq == 0 {
153 if fbuf[q] == (93 as u8) { closed = 1; fq = 1 }
154 else { if sl_isid(fbuf[q] as i64) == 1 { if k < 120 { cur[k] = fbuf[q]; k = k + 1 } q = q + 1 } else { okid = 0; fq = 1 } }
155 }
156 }
157 cur[k] = 0 as u8
158 var cmp: i64 = 0
159 if closed == 1 { if okid == 1 { if k > 0 {
160 var r: i64 = q + 1
161 var fr: i64 = 0
162 while fr == 0 {
163 if r >= brace { fr = 1 }
164 if fr == 0 { if fbuf[r] == (32 as u8) { r = r + 1 } else { fr = 1 } }
165 }
166 if r + 1 < brace { if fbuf[r + 1] == (61 as u8) { if fbuf[r] == (33 as u8) { cmp = 1 } if fbuf[r] == (61 as u8) { cmp = 1 } } }
167 } } }
168 if cmp == 1 {
169 var depth: i64 = 1
170 var b: i64 = brace + 1
171 var bend: i64 = 0 - 1
172 var fbd: i64 = 0
173 while fbd == 0 {
174 if b >= n { fbd = 1 }
175 if fbd == 0 {
176 if fbuf[b] == (123 as u8) { depth = depth + 1 }
177 if fbuf[b] == (125 as u8) { depth = depth - 1; if depth == 0 { bend = b; fbd = 1 } }
178 if fbd == 0 { b = b + 1 }
179 }
180 }
181 if bend > 0 {
182 var j: i64 = brace + 1
183 while j < bend {
184 var bound: i64 = 1
185 if sl_isid(fbuf[j - 1] as i64) == 1 { bound = 0 }
186 if bound == 1 { if sl_at(fbuf, j, n, cur) == 1 {
187 let after: i64 = j + k
188 if sl_isid(fbuf[after] as i64) == 0 {
189 var u: i64 = after
190 var fu: i64 = 0
191 while fu == 0 {
192 if u >= bend { fu = 1 }
193 if fu == 0 { if fbuf[u] == (32 as u8) { u = u + 1 } else { fu = 1 } }
194 }
195 if u + 1 < bend { if fbuf[u] == (61 as u8) { if fbuf[u + 1] != (61 as u8) {
196 var v: i64 = u + 1
197 var fv: i64 = 0
198 while fv == 0 {
199 if v >= bend { fv = 1 }
200 if fv == 0 { if fbuf[v] == (32 as u8) { v = v + 1 } else { fv = 1 } }
201 }
202 var val: i64 = 0
203 var nd: i64 = 0
204 var d: i64 = v
205 var fd: i64 = 0
206 while fd == 0 {
207 if d >= bend { fd = 1 }
208 if fd == 0 { let ch: i64 = fbuf[d] as i64; if ch >= 48 { if ch <= 57 { val = val * 10 + (ch - 48); nd = nd + 1; d = d + 1 } else { fd = 1 } } else { fd = 1 } }
209 }
210 if nd > 0 { if val >= 2 { if sl_isid(fbuf[d] as i64) == 0 { outval[0] = val; return j } } }
211 } } }
212 }
213 } }
214 j = j + 1
215 }
216 }
217 }
218 } }
219 } }
220 i = i + 1
221 }
222 return 0 - 1
223}
224
225// 1-based line number of a byte offset. A rule that reports a FILE and not a LINE cannot be
226// adjudicated without re-deriving every hit by hand, which is what made the first two drafts of
227// rule 3 unfalsifiable: 212 files, no way to read one.
228// ★★★★★ A COUNT WITHOUT A WORKLIST IS NOT ACTIONABLE, AND A WORKLIST WITHOUT THE LOCATION IS STILL
229// ONE STEP SHORT.
230func sl_lineno(fbuf: *u8, off: i64) -> i64 {
231 var ln: i64 = 1
232 var q: i64 = 0
233 while q < off {
234 if fbuf[q] == (10 as u8) { ln = ln + 1 }
235 q = q + 1
236 }
237 return ln
238}
239
240// ---- RULE 3: A BITWISE `&` THAT IS AN OPERAND OF A COMPARISON, UNPARENTHESISED ----
241//
242// if x & MASK == v { ... }
243//
244// does NOT test the masked bits. In this dialect -- as in C -- `==` binds TIGHTER than `&`, so the
245// expression is `x & (MASK == v)`: the comparison collapses to 0 or 1 and THE MASK IS DISCARDED. It
246// compiles clean, and it is invisible for every input where the two readings happen to agree, which
247// is exactly why it survives review and testing.
248//
249// MEASURED COST, 2026-09-03, the day this rule was written -- two real defects in the shipped tree:
250// nx_emu_rv64.nx:163 `if (w >> 30) & 1 == 0` -- the SRLI/SRAI discriminator. It parses as
251// `(w>>30) & (1==0)` = 0, i.e. ALWAYS FALSE, so EVERY RISC-V logical right
252// shift silently performed an ARITHMETIC shift. Invisible for non-negative
253// values, and the only rv64 test in the estate used non-negative values.
254// Its 32-bit twin 55 lines below had carried the parentheses all along --
255// a fix present in one verb and absent from its sibling.
256// nx_crypsis_test.nx:29 `if (enc[35] as i64) & 255 == (payload[0] as i64) & 255` -- compared ONE
257// BIT instead of a byte, inside a crypto test.
258// Four further sites of the form `& 1 == 1` are accidentally correct ONLY because `1 == 1` is 1;
259// change the mask and they break in silence. They are flagged too, because the remedy is identical
260// and always semantics-preserving: wrap the mask.
261//
262// PRECISION (the FP rate this rule is tightened to): scan from the `&` to end of line tracking paren
263// depth. A `)` that closes BEFORE the comparison means the `&` was ALREADY parenthesised, so it is
264// not a hit -- that is what makes the corrected form `((w >> 30) & 1) == 0` pass. `&&` is excluded
265// in both directions: `==` binding tighter than `&&` is correct and idiomatic. Comment lines are
266// skipped, because this header prints the defective idiom as its own worked example.
267// Returns the offset of the offending `&`, or -1.
268// FIRST DRAFT MEASURED 212 HITS ON 19,217 FILES AND THEY WERE FALSE POSITIVES. Reading them --
269// which is what the first draft of any detector is FOR -- named three buckets the naive
270// forward-scan could not see, every one of them a REAL construct in this tree:
271// `let a: i64=i&1; ... if (a^b^c)==1 {` the `&` and the `==` are SEPARATE STATEMENTS
272// `"A: indirect call &add == 7"` the `&` is inside a STRING LITERAL
273// `foo(a & b, c == d)` the `&` and the `==` are separate ARGUMENTS
274// So the scan is line-based and stops at a statement boundary (`;` `{` `}`), ignores anything
275// inside quotes, drops the candidate when a `,` separates it from the comparison at the same
276// depth, and drops it when a `)` closes below the depth the `&` was seen at -- which is what
277// makes the corrected `((w >> 30) & 1) == 0` pass while the defective `(w >> 30) & 1 == 0` fails.
278// ★★★★★ A DETECTOR WITH FALSE POSITIVES IS WORSE THAN NONE -- this organ says so in its own
279// header, and the first draft of this rule broke that rule before it was measured.
280// Start of the line AFTER the one containing off. Lets the caller resume a scan past a hit so
281// EVERY site in a file is reported, not just the first. Reporting one hit per FILE under-reports
282// the population and turns a sweep into a series of passes: draining this rule the first time took
283// eight passes (24-14-12-8-5-4-2-0) purely because each pass could only surface the next instance.
284// ★★★★★ A COUNT THAT CAN ONLY REPORT ONE MEMBER PER CONTAINER IS A FLOOR, NOT A POPULATION.
285func sl_next_line(fbuf: *u8, n: i64, off: i64) -> i64 {
286 var q: i64 = off
287 var f: i64 = 0
288 while f == 0 {
289 if q >= n { f = 1 }
290 if f == 0 {
291 if fbuf[q] == (10 as u8) { q = q + 1; f = 1 } else { q = q + 1 }
292 }
293 }
294 return q
295}
296
297// `start` resumes the scan at a line boundary. Callers pass 0 for the first call and
298// sl_next_line(previous hit) thereafter. KNOWN AND DECLARED LIMIT: a line carrying TWO such sites
299// reports only the first, because the resume is line-granular -- measured on this tree every
300// offending line carried exactly one, so the floor and the value coincide here, but it is a floor.
301func sl_rule3(fbuf: *u8, n: i64, start: i64, cur: *u8, outval: *i64) -> i64 {
302 var i: i64 = start
303 var hit: i64 = 0 - 1
304 cur[0] = 0 as u8
305 while i < n {
306 if hit >= 0 { i = n }
307 if hit < 0 {
308 var e: i64 = i
309 var fe: i64 = 0
310 while fe == 0 {
311 if e >= n { fe = 1 }
312 if fe == 0 { if fbuf[e] == (10 as u8) { fe = 1 } else { e = e + 1 } }
313 }
314 if sl_line_is_comment(fbuf, i, n) == 0 {
315 var p: i64 = i
316 var instr: i64 = 0
317 var depth: i64 = 0
318 var cand: i64 = 0 - 1
319 var cdep: i64 = 0
320 while p < e {
321 let c: i64 = fbuf[p] as i64
322 // SNAPSHOT the string state: without it the closing quote turns the string
323 // OFF and the very next test turns it straight back ON, the no-else defect.
324 let wasstr: i64 = instr
325 var step: i64 = 1
326 if wasstr == 1 { if c == 34 { instr = 0 } }
327 if wasstr == 0 {
328 if c == 34 { instr = 1 }
329 if c == 47 { if p + 1 < e { if fbuf[p + 1] == (47 as u8) { p = e; step = 0 } } }
330 if c == 40 { depth = depth + 1 }
331 if c == 41 {
332 depth = depth - 1
333 if cand >= 0 { if depth < cdep { cand = 0 - 1 } }
334 }
335 if c == 59 { cand = 0 - 1 }
336 if c == 123 { cand = 0 - 1 }
337 if c == 125 { cand = 0 - 1 }
338 if c == 44 { if cand >= 0 { if depth == cdep { cand = 0 - 1 } } }
339 if c == 38 {
340 var amp: i64 = 1
341 if p + 1 < e { if fbuf[p + 1] == (38 as u8) { amp = 0 } }
342 if p > i { if fbuf[p - 1] == (38 as u8) { amp = 0 } }
343 if amp == 1 { cand = p; cdep = depth }
344 }
345 var iscmp: i64 = 0
346 if c == 61 { if p + 1 < e { if fbuf[p + 1] == (61 as u8) { iscmp = 1 } } }
347 if c == 33 { if p + 1 < e { if fbuf[p + 1] == (61 as u8) { iscmp = 1 } } }
348 if iscmp == 1 {
349 if cand >= 0 { if depth == cdep { hit = cand } }
350 if step == 1 { p = p + 1 }
351 }
352 }
353 if step == 1 { p = p + 1 }
354 }
355 }
356 i = e + 1
357 }
358 }
359 outval[0] = hit
360 return hit
361}
362
363func main(argc: i64, argv: *i64) -> i64 {
364 var dir: *u8 = SL_DIR
365 var dirset: i64 = 0
366 var quiet: i64 = 0
367 var accept: i64 = 0
368 var wantr3: i64 = 0
369 var a: i64 = 1
370 while a < argc {
371 let s: *u8 = argv[a] as *u8
372 if mp_streq(s, "--dir" as *u8) == 1 { if a + 1 < argc { dir = argv[a + 1] as *u8; dirset = 1; a = a + 1 } }
373 if mp_streq(s, "--quiet" as *u8) == 1 { quiet = 1 }
374 if mp_streq(s, "--accept" as *u8) == 1 { accept = 1 }
375 // RULE 3 is OPT-IN until it measures a zero false-positive rate on the real tree. The
376 // promoted default therefore stays exactly the trustworthy two-rule lint, and iterating on
377 // rule 3 cannot degrade what every other caller sees.
378 if mp_streq(s, "--rule3" as *u8) == 1 { wantr3 = 1 }
379 a = a + 1
380 }
381
382 let msg: *u8 = sys_mmap(SL_MAGIC_8192)
383 let names: *u8 = sys_mmap(SL_MAXF * 128)
384 let fbuf: *u8 = sys_mmap(SL_FBUF)
385 let path: *u8 = sys_mmap(SL_MAGIC_4096)
386 let outb: *u8 = sys_mmap(SL_MAGIC_262144)
387 let lhsb: *u8 = sys_mmap(256)
388 let r2val: *i64 = sys_mmap(16) as *i64
389 let slbase: *u8 = sys_mmap(SL_MAGIC_4096)
390 if gk_ops_path(slbase, "srclint.baseline" as *u8) == 0 {
391 var mb2: i64 = mp_cat(msg, 0, "*** nx_srclint: REFUSED -- cannot resolve the baseline dir on this host. ***\n" as *u8)
392 mp_say(msg, mb2)
393 return 1
394 }
395 var oo: i64 = 0
396
397 // THE CORPUS comes from gk_corpus_scan -- the estate's single definition of "the tree" -- not
398 // from a directory constant. SL_DIR scanned _hdl_build only: 7,159 of 18,561 files, so a lint
399 // that reports "4 real hits estate-wide" was reporting on 38.6% of the estate.
400 // ★★★★★★ AN "ESTATE-WIDE" LINT WITH A ONE-DIRECTORY CONSTANT IS A LOCAL LINT WEARING A GLOBAL NAME.
401 var cnt: i64 = 0
402 if dirset == 0 { cnt = gk_corpus_scan(names, MP_SLOT, SL_MAXF) }
403 if dirset == 1 { cnt = gk_dirscan(dir, 0 as *u8, names, MP_SLOT, SL_MAXF, 0) }
404 if cnt == (0 - 2) {
405 var m2: i64 = mp_cat(msg, 0, "*** nx_srclint: REFUSED -- corpus exceeds SL_MAXF; a truncated lint is not a lint. ***\n" as *u8)
406 mp_say(msg, m2)
407 return 1
408 }
409 if cnt == (0 - 3) {
410 var m3: i64 = mp_cat(msg, 0, "*** nx_srclint: REFUSED -- a source path exceeds the name slot. ***\n" as *u8)
411 mp_say(msg, m3)
412 return 1
413 }
414 if cnt <= 0 {
415 var me: i64 = mp_cat(msg, 0, "*** nx_srclint: REFUSED -- could not scan the source tree. ***\n" as *u8)
416 mp_say(msg, me)
417 return 1
418 }
419 var mcorp: i64 = mp_cat(msg, 0, " corpus=" as *u8)
420 mcorp = mp_catn(msg, mcorp, cnt)
421 if dirset == 0 { mcorp = mp_cat(msg, mcorp, " files (WHOLE compile corpus)\n" as *u8) }
422 if dirset == 1 { mcorp = mp_cat(msg, mcorp, " files (NARROWED by --dir; NOT the whole tree)\n" as *u8) }
423 mp_say(msg, mcorp)
424
425 // The baseline ALWAYS carries this header, so "clean" and "unarmed" are different files.
426 // A zero-hit run used to write a ZERO-BYTE baseline, which reads back as bn==0 -- i.e. "no
427 // baseline yet" -- so the ratchet DISARMED ITSELF THE MOMENT THE TREE BECAME CLEAN and the
428 // next regression would have been greeted as a first run and silently adopted.
429 // ★★★★★★ A RATCHET THAT ENCODES "NOTHING IS WRONG" AS AN EMPTY FILE CANNOT TELL A CLEAN TREE
430 // FROM AN UNARMED DETECTOR -- AND IT FAILS OPEN EXACTLY WHEN YOU SUCCEED.
431 oo = mp_cat(outb, oo, "# corpus=" as *u8)
432 oo = mp_catn(outb, oo, cnt)
433 oo = mp_cat(outb, oo, "\n" as *u8)
434
435 var nfiles: i64 = 0
436 var nhit: i64 = 0
437 var m: i64 = 0
438
439 var fi: i64 = 0
440 while fi < cnt {
441 // gk_corpus_scan returns ABSOLUTE paths; the dir re-join was the seam where a second
442 // source directory could not be represented at all.
443 let nm: *u8 = mp_nameptr(names, fi)
444 let n: i64 = mp_readf(nm, fbuf, SL_FBUF)
445 if n > 0 {
446 nfiles = nfiles + 1
447 var filehit: i64 = 0
448 var i: i64 = 0
449 while i < n {
450 // The idiom, exactly: `X = <something> + N` ... later ... `X = X - N`.
451 // Anchor on the `+ N`, recover X from the assignment that contains it, then require a
452 // restore that names X on BOTH sides. Identity is what separates the defect from
453 // arithmetic.
454 if sl_at(fbuf, i, n, "+ " as *u8) == 1 {
455 // SKIP COMMENT LINES. This organ's own header prints the defective idiom as its
456 // worked example, so the first working build accused itself -- and an accusation
457 // against documentation is still a false positive.
458 // ★ A RULE THAT CANNOT TELL CODE FROM THE COMMENT DESCRIBING IT WILL FLAG EVERY
459 // EXPLANATION OF THE BUG IT HUNTS.
460 var bl: i64 = i
461 var fb: i64 = 0
462 while fb == 0 {
463 if bl <= 0 { fb = 1 }
464 if fb == 0 { if fbuf[bl - 1] == (10 as u8) { fb = 1 } else { bl = bl - 1 } }
465 }
466 var sp: i64 = bl
467 var fsp: i64 = 0
468 while fsp == 0 {
469 if sp >= i { fsp = 1 }
470 if fsp == 0 { if fbuf[sp] == (32 as u8) { sp = sp + 1 } else { fsp = 1 } }
471 }
472 var iscmt: i64 = 0
473 if sp + 1 < n { if fbuf[sp] == (47 as u8) { if fbuf[sp + 1] == (47 as u8) { iscmt = 1 } } }
474 if iscmt == 1 { i = i + 1 }
475 if iscmt == 0 {
476 // walk left to the `=` of this assignment (same line only)
477 var eq: i64 = i - 1
478 var lhsok: i64 = 0
479 var fe: i64 = 0
480 while fe == 0 {
481 if eq < 0 { fe = 1 }
482 if fe == 0 { if fbuf[eq] == (10 as u8) { fe = 1 } }
483 if fe == 0 { if fbuf[eq] == (61 as u8) { lhsok = 1; fe = 1 } }
484 if fe == 0 { eq = eq - 1 }
485 }
486 if lhsok == 1 { lhsok = sl_lhs(fbuf, eq, lhsb) }
487 // ★★★★★★ THE DEFECT ASSIGNS FROM THE LIMIT, NOT FROM ITSELF.
488 // `X = X + N` is an ACCUMULATOR (a bit counter, a colour channel, a running sum) and
489 // is correct code. The cursor-sentinel is `X = <limit> + N` -- the loop bound on the
490 // right-hand side, which is what makes the restore land on the bound instead of the
491 // position. Without this test the rule flagged 4 files, ALL FALSE POSITIVES:
492 // evo_disc0 (`acc = acc + 3`), nx_apistack_oidc (base64 `bits = bits + 6`),
493 // nx_denoise_spectral_gate (`v = v + 5`), nx_persongen_render_gate (`cr = cr + 12`).
494 // ★★★★★ MEASURE THE FALSE-POSITIVE RATE ON REAL DATA AND TIGHTEN UNTIL IT IS ZERO
495 // WITHOUT LOSING THE TRUE POSITIVE -- 0 true / 4 false is a detector that would have
496 // taught everyone to ignore it within a day.
497 if lhsok > 0 {
498 var rp: i64 = eq + 1
499 var fr: i64 = 0
500 while fr == 0 {
501 if rp >= i { fr = 1 }
502 if fr == 0 { if fbuf[rp] == (32 as u8) { rp = rp + 1 } else { fr = 1 } }
503 }
504 if sl_at(fbuf, rp, n, lhsb) == 1 {
505 var bnd: i64 = 1
506 if rp + mp_len(lhsb) < n { if sl_isid(fbuf[rp + mp_len(lhsb)] as i64) == 1 { bnd = 0 } }
507 if bnd == 1 { lhsok = 0 }
508 }
509 }
510 var d: i64 = i + 2
511 var val: i64 = 0
512 var nd: i64 = 0
513 var fin: i64 = 0
514 while fin == 0 {
515 if d >= n { fin = 1 }
516 if fin == 0 {
517 let c: i64 = fbuf[d] as i64
518 if c >= 48 { if c <= 57 { val = val * 10 + (c - 48); nd = nd + 1; d = d + 1 } }
519 if c < 48 { fin = 1 }
520 if c > 57 { fin = 1 }
521 }
522 }
523 // the idiom always uses a small out-of-band bump; 2..99 keeps ordinary +1 arithmetic out
524 if lhsok > 0 { if nd > 0 { if val >= 2 { if val <= 99 {
525 // require the RESTORE to name the same variable on both sides: `X = X - N`
526 var j: i64 = d
527 let lim: i64 = d + SL_WIN
528 var found: i64 = 0
529 var fj: i64 = 0
530 while fj == 0 {
531 if j >= n { fj = 1 }
532 if j >= lim { fj = 1 }
533 if fj == 0 {
534 // WHOLE-IDENTIFIER match: `e` must not match inside `else`. Without the
535 // boundary check a one-letter cursor name matches half the file.
536 var bound: i64 = 1
537 if j > 0 { if sl_isid(fbuf[j - 1] as i64) == 1 { bound = 0 } }
538 if bound == 1 { if j + mp_len(lhsb) < n { if sl_isid(fbuf[j + mp_len(lhsb)] as i64) == 1 { bound = 0 } } }
539 if bound == 1 { if sl_at(fbuf, j, n, lhsb) == 1 {
540 // `X` then optional spaces then `= X - N`
541 // ⚠ A dead space-skipping loop sat here that set its own cursor to
542 // n+1 and never recovered -- the CURSOR-SENTINEL defect, inside the
543 // linter written to detect it, making the linter report 0 hits on a
544 // planted example. ★★★★★★ A DETECTOR THAT FINDS NOTHING HAS NOT
545 // FOUND NOTHING UNTIL IT HAS FOUND SOMETHING PLANTED.
546 var u: i64 = j + mp_len(lhsb)
547 var fs: i64 = 0
548 while fs == 0 {
549 if u >= n { fs = 1 }
550 if fs == 0 { if fbuf[u] == (32 as u8) { u = u + 1 } else { fs = 1 } }
551 }
552 if u < n { if fbuf[u] == (61 as u8) {
553 var v: i64 = u + 1
554 var fv: i64 = 0
555 while fv == 0 {
556 if v >= n { fv = 1 }
557 if fv == 0 { if fbuf[v] == (32 as u8) { v = v + 1 } else { fv = 1 } }
558 }
559 if sl_at(fbuf, v, n, lhsb) == 1 {
560 var y: i64 = v + mp_len(lhsb)
561 if sl_at(fbuf, y, n, " - " as *u8) == 1 {
562 var d2: i64 = y + 3
563 var v2: i64 = 0
564 var n2: i64 = 0
565 var f2: i64 = 0
566 while f2 == 0 {
567 if d2 >= n { f2 = 1 }
568 if f2 == 0 {
569 let c2: i64 = fbuf[d2] as i64
570 if c2 >= 48 { if c2 <= 57 { v2 = v2 * 10 + (c2 - 48); n2 = n2 + 1; d2 = d2 + 1 } }
571 if c2 < 48 { f2 = 1 }
572 if c2 > 57 { f2 = 1 }
573 }
574 }
575 if n2 > 0 { if v2 == val { found = 1; fj = 1 } }
576 }
577 }
578 } }
579 } }
580 if fj == 0 { j = j + 1 }
581 }
582 }
583 if found == 1 {
584 if filehit == 0 {
585 nhit = nhit + 1
586 filehit = 1
587 oo = mp_cat(outb, oo, nm)
588 outb[oo] = 10 as u8
589 oo = oo + 1
590 if quiet == 0 {
591 m = mp_cat(msg, 0, " CURSOR-SENTINEL " as *u8)
592 m = mp_cat(msg, m, nm)
593 m = mp_cat(msg, m, " `+ " as *u8)
594 m = mp_catn(msg, m, val)
595 m = mp_cat(msg, m, "` paired with `- " as *u8)
596 m = mp_catn(msg, m, val)
597 m = mp_cat(msg, m, "` -- the exit marker is written into the cursor; the restore lands on the limit, not the position found.\n" as *u8)
598 mp_say(msg, m)
599 }
600 }
601 }
602 } } } }
603 }
604 }
605 i = i + 1
606 }
607 // ---- RULE 2 (2026-09-02): the literal-exit sentinel in an indexed-condition loop ----
608 let r2: i64 = sl_rule2(fbuf, n, lhsb, r2val)
609 if r2 >= 0 {
610 if filehit == 0 {
611 nhit = nhit + 1
612 filehit = 1
613 oo = mp_cat(outb, oo, nm)
614 outb[oo] = 10 as u8
615 oo = oo + 1
616 }
617 if quiet == 0 {
618 m = mp_cat(msg, 0, " LITERAL-EXIT-SENTINEL " as *u8)
619 m = mp_cat(msg, m, nm)
620 m = mp_cat(msg, m, " `while X[" as *u8)
621 m = mp_cat(msg, m, lhsb)
622 m = mp_cat(msg, m, "]` body writes `" as *u8)
623 m = mp_cat(msg, m, lhsb)
624 m = mp_cat(msg, m, " = " as *u8)
625 m = mp_catn(msg, m, r2val[0])
626 m = mp_cat(msg, m, "` -- the condition reads through the cursor and the exit is a literal past the key; rodata decides whether the loop ends (the supervisor spin class).\n" as *u8)
627 mp_say(msg, m)
628 }
629 }
630 // ---- RULE 3: BUILT, MEASURED, AND DELIBERATELY NOT WIRED (2026-09-03) ----
631 // sl_rule3 above is complete and its hazard is REAL -- it is the precedence trap that
632 // made every RISC-V SRLI an arithmetic shift, and a crypto test compare one bit. But
633 // MEASURED ON THE WHOLE 19,217-FILE CORPUS IT REPORTS 212 FILES, AND THE ONES READ WERE
634 // FALSE POSITIVES. The first draft missed statement boundaries and string literals; the
635 // second draft handles those and STILL reports 212, and nx_fpga_adder.nx -- whose only
636 // candidate line is `let a: i64=i&1; ... if (a^b^c)==1` and is plainly correct code --
637 // is still among them. The rule ALSO does not print the offending offset, so its output
638 // cannot be adjudicated without re-deriving each hit by hand.
639 // ★★★★★ A DETECTOR WITH FALSE POSITIVES IS WORSE THAN NONE -- this organ says exactly
640 // that in its own header, so shipping this rule wired would break the standard the organ
641 // exists to hold. It stays unwired until it prints its offset AND measures a zero false
642 // positive rate on the real tree, which is the same bar rules 1 and 2 had to clear.
643 // The two real defects it was written for are already FIXED and parenthesised.
644 // RULE 3 IS NOW ON BY DEFAULT AND IN THE RATCHET -- it earned both, measured:
645 // draft 1: 212 files, no location, false positives -> unfalsifiable, refused
646 // draft 2 (statement boundaries, string literals, argument commas, paren depth)
647 // plus FILE:LINE reporting: 24 hits, ALL 24 ADJUDICATED BY HAND,
648 // ZERO false positives, ~17 REAL DEFECTS.
649 // What it caught: nx_parallel_run masked a child EXIT STATUS down to bit 0;
650 // nx_capability_no_regression_check tested `& 2 == 2`, i.e. the WRONG BIT, inside a
651 // regression detector; nx_f32_log_test asserted `& 1 != 1` which is `x & 0` and can
652 // NEVER fire -- a vacuous test; and ten byte-comparison assertions across the codec,
653 // css, layout and tls suites compared ONE BIT instead of a whole byte.
654 // All 38 sites were fixed before this rule was wired, so it goes into the ratchet
655 // against a CLEAN tree and cannot be a permanently-red detector.
656 // --rule3 is kept as an accepted no-op so any existing caller keeps working.
657 // EVERY site, not just the first: resume the scan past each hit.
658 var r3s: i64 = 0
659 var r3go: i64 = 1
660 while r3go == 1 {
661 var r3: i64 = sl_rule3(fbuf, n, r3s, lhsb, r2val)
662 if r3 < 0 { r3go = 0 }
663 if r3 >= 0 {
664 r3s = sl_next_line(fbuf, n, r3)
665 if filehit == 0 {
666 nhit = nhit + 1
667 filehit = 1
668 oo = mp_cat(outb, oo, nm)
669 outb[oo] = 10 as u8
670 oo = oo + 1
671 }
672 if quiet == 0 {
673 m = mp_cat(msg, 0, " BITWISE-VS-COMPARE " as *u8)
674 m = mp_cat(msg, m, nm)
675 m = mp_cat(msg, m, ":" as *u8)
676 m = mp_catn(msg, m, sl_lineno(fbuf, r3))
677 m = mp_cat(msg, m, " an unparenthesised `&` is an operand of `==` or `!=`. `==` binds TIGHTER, so `x & M == v` means `x & (M == v)` and THE MASK IS DISCARDED. Remedy: `(x & M) == v`.\n" as *u8)
678 mp_say(msg, m)
679 }
680 }
681 }
682 }
683 fi = fi + 1
684 }
685
686 // ---- name-set ratchet, same contract as nx_unwired ----
687 let bb: *u8 = sys_mmap(SL_MAGIC_262144)
688 let bn: i64 = mp_readf(slbase, bb, SL_MAGIC_262000)
689 var nadd: i64 = 0
690 var rc: i64 = 0
691 if bn > 0 {
692 var p: i64 = 0
693 while p < oo {
694 var e: i64 = p
695 var f3: i64 = 0
696 while f3 == 0 {
697 if e >= oo { f3 = 1 }
698 if f3 == 0 { if outb[e] == (10 as u8) { f3 = 1 } }
699 if f3 == 0 { e = e + 1 }
700 }
701 // The "# corpus=N" header is METADATA, not a finding. Left in the diff it becomes a
702 // phantom entry the instant the corpus size changes, so a bite test that planted ONE
703 // bad file reported "RED: 2 NEW". ★★★★★ AN ALARM THAT MISCOUNTS BY ONE TEACHES THE
704 // READER TO DISTRUST EVERY NUMBER BESIDE IT -- a header must never be a row.
705 var ishdr: i64 = 0
706 if outb[p] == (35 as u8) { ishdr = 1 }
707 if e > p { if ishdr == 0 {
708 // is this name in the baseline?
709 var seen: i64 = 0
710 var q: i64 = 0
711 while q < bn {
712 var e2: i64 = q
713 var f4: i64 = 0
714 while f4 == 0 {
715 if e2 >= bn { f4 = 1 }
716 if f4 == 0 { if bb[e2] == (10 as u8) { f4 = 1 } }
717 if f4 == 0 { e2 = e2 + 1 }
718 }
719 if e2 - q == e - p {
720 var same: i64 = 1
721 var z: i64 = 0
722 while z < e - p { if bb[q + z] != outb[p + z] { same = 0; z = e - p } else { z = z + 1 } }
723 if same == 1 { seen = 1; q = bn }
724 }
725 if q < bn { q = e2 + 1 }
726 }
727 if seen == 0 {
728 nadd = nadd + 1
729 m = mp_cat(msg, 0, " *** NEW CURSOR-SENTINEL: " as *u8)
730 var z2: i64 = 0
731 while z2 < e - p { msg[m] = outb[p + z2]; m = m + 1; z2 = z2 + 1 }
732 m = mp_cat(msg, m, " ***\n" as *u8)
733 mp_say(msg, m)
734 }
735 } }
736 p = e + 1
737 }
738 }
739
740 m = mp_cat(msg, 0, "nx_srclint: " as *u8)
741 m = mp_catn(msg, m, nfiles)
742 m = mp_cat(msg, m, " sources, " as *u8)
743 m = mp_catn(msg, m, nhit)
744 m = mp_cat(msg, m, " files carry the CURSOR-SENTINEL idiom" as *u8)
745 if bn <= 0 { m = mp_cat(msg, m, " (no baseline yet -- recording the current set)\n" as *u8) }
746 if bn > 0 {
747 if nadd > 0 { m = mp_cat(msg, m, " *** RED: " as *u8); m = mp_catn(msg, m, nadd); m = mp_cat(msg, m, " NEW ***\n" as *u8); rc = 1 }
748 if nadd == 0 { m = mp_cat(msg, m, " GREEN: no new occurrence since the baseline.\n" as *u8) }
749 }
750 mp_say(msg, m)
751
752 var writeit: i64 = 0
753 if nadd == 0 { writeit = 1 }
754 if accept == 1 { writeit = 1 }
755 if writeit == 1 {
756 let wf: i64 = sys_openat_wr(slbase, 420)
757 if wf >= 0 { mp_write_all(wf, outb, oo); sys_close(wf) }
758 if accept == 1 { if nadd > 0 { rc = 0 } }
759 }
760 return rc
761}