code wiki / _hdl_build / nx_janitor_caps.nx

nx_janitor_caps.nx source

↩ module page · 125 lines · 7516 B

1// nx_janitor_caps.nx -- the JANITOR's MAGIC-NUMBER-CAP detector (the missing X-JAN rule). Finds the 2// SILENT-TRUNCATION cap smell -- the exact bug class that just cost us a "stored-not-served" outage in the 3// seg-store (a hardcoded 256/260-segment array that dropped 680 of 936 segments with NO error). READ-ONLY: 4// it reports candidates; it never edits. The detector CORE lives in nx_cap_detect_lib.nx (shared with the 5// gate); this file is the tree-WALK + report. A file is flagged ONLY when all THREE parts co-occur: 6// (1) a FIXED-COUNT array: sys_mmap( K * <literal-N> ) -- a literal count right after a '*' 7// (2) a FILL/INDEX bound on N: '< N' | '<= N' | '>= N' | '> N' with that SAME literal N 8// (3) an UNBOUNDED source: sys_read( | getdents | fetch | recvfrom | ss_readall in the file 9// Data-driven sizing (a VARIABLE after '*') is invisible to the detector -- only the bare-literal cap flags. 10// nx_janitor_caps [scan_root] default scan_root = runtime 11// license_tier: ORIGINAL | genealogy_id: nishi_janitor_caps_2026_07_15 12import "nx_syscalls.nx" 13import "nx_cap_detect_lib.nx" 14 15// ---- sizing constants (named; no magic numbers -- the detector obeys its own rule) ---- 16const JC_PATH_SLOT: i64 = 768 // bytes per queued directory path 17const JC_QUEUE_CAP: i64 = 16384 // max directories in the BFS queue 18const JC_DENT_BUF: i64 = 65536 // getdents64 read buffer 19const JC_FILE_CAP: i64 = 4194304 // per-.nx read buffer (reused); a >4MB .nx would truncate (named, honest) 20const JC_DT_OFF: i64 = 16 // d_reclen offset in linux_dirent64 21const JC_NAME_OFF: i64 = 19 // d_name offset in linux_dirent64 22 23func jc_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 24func jc_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); 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{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 } 25func jc_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 26func jc_eq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8){ if a[i]!=b[i]{return 0} i=i+1 } if b[i]!=(0 as u8){return 0} return 1 } 27func jc_ends(path: *u8, pl: i64, ext: *u8) -> i64 { 28 let el: i64=jc_slen(ext); if el>pl { return 0 } 29 var i: i64=0; while i<el { if path[pl-el+i]!=ext[i] { return 0 } i=i+1 } return 1 30} 31func jc_join(dst: *u8, dir: *u8, name: *u8) -> i64 { 32 var o: i64=0; var i: i64=0 33 while dir[i]!=(0 as u8){ dst[o]=dir[i]; o=o+1; i=i+1 } 34 dst[o]=47 as u8; o=o+1 35 i=0; while name[i]!=(0 as u8){ dst[o]=name[i]; o=o+1; i=i+1 } 36 dst[o]=0 as u8; return o 37} 38func jc_getdents(fd: i64, buf: *u8, count: i64) -> i64 { return __syscall(SYS_GETDENTS64, fd, buf, count, 0, 0, 0) } 39func jc_isdir(path: *u8, st: *u8) -> i64 { 40 let r: i64=__syscall(262, 0-100, path, st, 0, 0, 0) 41 if r<0 { return 0-1 } 42 let mode: i64=(st[24] as i64) | ((st[25] as i64)<<8) | ((st[26] as i64)<<16) | ((st[27] as i64)<<24) 43 if (mode & 0xF000)==0x4000 { return 1 } 44 return 0 45} 46func jc_read(path: *u8, buf: *u8, cap: i64) -> i64 { 47 let fd: i64=sys_openat_rd(path); if fd<0 { return 0 } 48 var total: i64=0; var nrd: i64=sys_read(fd, buf, cap) 49 while nrd>0 { total=total+nrd; if total>=cap { nrd=0 } else { nrd=sys_read(fd, ((buf as i64)+total) as *u8, cap-total) } } 50 sys_close(fd); return total 51} 52 53// walk scan_root's .nx graph; FLAG each file with the full three-part silent-cap signature. 54func jc_walk(scan_root: *u8, outs: *i64) -> i64 { 55 let qbuf: *u8=sys_mmap(JC_PATH_SLOT*JC_QUEUE_CAP) 56 let gbuf: *u8=sys_mmap(JC_DENT_BUF) 57 let stbuf: *u8=sys_mmap(256) 58 let fbuf: *u8=sys_mmap(JC_FILE_CAP) 59 let sbuf: *u8=sys_mmap(JC_FILE_CAP) 60 let child: *u8=sys_mmap(JC_PATH_SLOT) 61 var qhead: i64=0; var qtail: i64=0 62 var ri: i64=0; while scan_root[ri]!=(0 as u8){ qbuf[ri]=scan_root[ri]; ri=ri+1 } qbuf[ri]=0 as u8; qtail=1 63 var scanned: i64=0; var flagged: i64=0 64 while qhead<qtail { 65 let dir: *u8=((qbuf as i64)+qhead*JC_PATH_SLOT) as *u8; qhead=qhead+1 66 let fd: i64=sys_openat_rd(dir) 67 if fd<0 { continue } 68 var nread: i64=jc_getdents(fd, gbuf, JC_DENT_BUF) 69 while nread>0 { 70 var off: i64=0 71 while off<nread { 72 let reclen: i64=(gbuf[off+JC_DT_OFF] as i64) | ((gbuf[off+JC_DT_OFF+1] as i64)<<8) 73 if reclen<=0 { off=nread } else { 74 let name: *u8=((gbuf as i64)+off+JC_NAME_OFF) as *u8 75 var skip: i64=0 76 if jc_eq(name,"." as *u8)==1 { skip=1 } 77 if jc_eq(name,".." as *u8)==1 { skip=1 } 78 if skip==0 { 79 jc_join(child, dir, name) 80 let isd: i64=jc_isdir(child, stbuf) 81 if isd==1 { 82 var vendored: i64=0 83 if jc_eq(name,"node_modules" as *u8)==1 { vendored=1 } 84 if jc_eq(name,".git" as *u8)==1 { vendored=1 } 85 if jc_eq(name,".alelane" as *u8)==1 { vendored=1 } 86 if vendored==0 { if qtail<JC_QUEUE_CAP { let dst: *u8=((qbuf as i64)+qtail*JC_PATH_SLOT) as *u8; var c: i64=0; while child[c]!=(0 as u8){ dst[c]=child[c]; c=c+1 } dst[c]=0 as u8; qtail=qtail+1 } } 87 } else { if isd==0 { 88 let pl: i64=jc_slen(child) 89 if jc_ends(child, pl, ".nx" as *u8)==1 { 90 let fn: i64=jc_read(child, fbuf, JC_FILE_CAP) 91 if fn>0 { 92 scanned=scanned+1 93 jc_strip_noncode(fbuf, fn, sbuf) // ignore string/comment matches -- only real code 94 let lit: i64=jc_mmap_scan(sbuf, fn) 95 if lit>0 { if jc_has_src(sbuf, fn)==1 { 96 flagged=flagged+1 97 jc_puts("FLAG " as *u8); jc_puts(child) 98 jc_puts(" count=" as *u8); jc_num(lit); jc_puts("\n" as *u8) 99 } } 100 } 101 } 102 } } 103 } 104 off=off+reclen 105 } 106 } 107 nread=jc_getdents(fd, gbuf, JC_DENT_BUF) 108 } 109 sys_close(fd) 110 } 111 outs[0]=scanned; outs[1]=flagged 112 return flagged 113} 114 115func main(argc: i64, argv: *i64) -> i64 { 116 var scan_root: *u8="runtime" as *u8 117 if argc>=2 { scan_root=argv[1] as *u8 } 118 jc_puts("=== nx_janitor_caps: silent-truncation CAP detector (fixed-count array + same-literal fill bound + unbounded source) ===\n" as *u8) 119 jc_puts(" scan_root=" as *u8); jc_puts(scan_root); jc_puts(" floor=" as *u8); jc_num(JC_MIN_COUNT); jc_puts("\n" as *u8) 120 let outs: *i64=sys_mmap(64) as *i64 121 jc_walk(scan_root, outs) 122 jc_puts("--- scanned=" as *u8); jc_num(outs[0]); jc_puts(" .nx files, FLAGGED=" as *u8); jc_num(outs[1]) 123 jc_puts(" (candidates: a fixed-count array whose literal also bounds a fill loop, in a file that reads an unbounded source -- review each; data-driven sizing makes the flag disappear) ---\n" as *u8) 124 return 0 125}