code wiki / (root) / nx_shipcheck.nx

nx_shipcheck.nx source

↩ module page · 537 lines · 20060 B

1// nx_shipcheck.nx -- SHIP-COMPLETE integration-orphan detector (POST-submit lane; operator law 2// feedback-ship-complete-lifecycle-standard 2026-07-21, ws=auto-shipcomplete-guards). 3// Counts integration orphans per class over the REAL registry surfaces: 4// noschema tool_allowlist.conf rows with NO schema row in knowledge/tool_schemas.conf 5// staleschema tool_schemas.conf rows whose tool is NOT in tool_allowlist.conf (ghost schema) 6// stagedref registry rows whose binary path contains .new (registered-but-never-promoted) 7// missingbin registry rows whose binary is ABSENT on disk (tools/call would exec-fail) 8// straynew stranded .new artifacts in the deploy root (one-level walk, DECLARED) 9// verb `listnew [root]` PRINTS those names (exit code = the count) -- see sc_scan_new's header for why. 10// noatlas registry tools absent from knowledge/registry/atlas_catalog.tsv col1 11// Composed context (owned elsewhere, echoed for the trend line, NEVER re-scanned or re-filed): 12// dupsrc last count from knowledge/status/dup_source.log (seq207 lane) 13// unreg_l003 last L003 measured from knowledge/status/law_warden.jrnl (warden lane) 14// frowjoin=-1 DECLARED UNMEASURED: frontier rows carry no ws column (F209 evidence gap). 15// verbs: scan [root] | beat [root] | file [root] [filer] 16// scan: sweep + print + O_APPEND one trend line to <root>/knowledge/status/shipcheck.log 17// beat: scan + auto-file debts via the ALLOWLIST-RESOLVED filer (default nx_debt) 18// file: scan + file via an INJECTED filer tool name (the gate passes argecho -- selftest 19// never writes the production debt plane; F872 harden pattern) 20// Descs are CANONICAL and COUNT-FREE so nx_debt content-idempotent add (F868) makes any 21// beat cadence spam-proof BY CONSTRUCTION. Envelope: per-file read caps DECLARED via capped=. 22// license_tier: ORIGINAL Read-only sweep + O_APPEND log + debt filing. No hw writes (Rule 26). 23import "nx_syscalls.nx" 24 25const SC_TAB: i64 = 9 26const SC_NL: i64 = 10 27const SC_HASH: i64 = 35 28const SC_DOT: i64 = 46 29const SC_SLASH: i64 = 47 30const SC_COLON: i64 = 58 31const SC_ZERO: i64 = 48 32const SC_NINE: i64 = 57 33const SC_MINUS: i64 = 45 34const SC_B10: i64 = 10 35const SC_B256: i64 = 256 36const SC_LC_N: i64 = 110 37const SC_LC_E: i64 = 101 38const SC_LC_W: i64 = 119 39const SC_BUFCAP: i64 = 262144 40const SC_LOGCAP: i64 = 1048576 41const SC_PATHCAP: i64 = 1024 42const SC_OUTCAP: i64 = 8192 43const SC_DESCCAP: i64 = 1024 44const SC_DIRCAP: i64 = 262144 45const SC_MODE_F: i64 = 420 46const SC_EXITRED: i64 = 3 47const SC_EXEFAIL: i64 = 127 48const SC_STATBUF: i64 = 160 49const SC_NEWLEN: i64 = 4 50const SC_SEV_MISSINGBIN: i64 = 7 51const SC_SEV_STAGEDREF: i64 = 7 52const SC_SEV_NOSCHEMA: i64 = 6 53const SC_SEV_STALESCHEMA: i64 = 5 54const SC_SEV_STRAYNEW: i64 = 5 55const SC_SEV_NOATLAS: i64 = 4 56 57static g_root: *u8 58static g_allow: *u8 59static g_an: i64 60static g_schema: *u8 61static g_sn: i64 62static g_atlas: *u8 63static g_atn: i64 64static g_scr: *u8 65static g_scr2: *u8 66static g_sp: *i64 67static g_rn: i64 68static g_hitcap: i64 69static g_sev: i64 70static g_c_allow: i64 71static g_c_schema: i64 72static g_c_noschema: i64 73static g_c_staleschema: i64 74static g_c_stagedref: i64 75static g_c_missingbin: i64 76static g_c_straynew: i64 77static g_c_dupsrc: i64 78static g_c_unreg: i64 79static g_c_noatlas: i64 80 81func sc_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 82 83func sc_cat(d: *u8, o: i64, s: *u8) -> i64 { 84 var i: i64 = 0 85 var p: i64 = o 86 while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } 87 d[p] = 0 as u8 88 return p 89} 90 91func sc_catn(d: *u8, o: i64, v: i64) -> i64 { 92 let t: *u8 = sys_mmap(32) 93 var m: i64 = v 94 var p: i64 = o 95 if m < 0 { d[p] = SC_MINUS as u8; p = p + 1; m = 0 - m } 96 var k: i64 = 0 97 if m == 0 { t[0] = SC_ZERO as u8; k = 1 } 98 while m > 0 { t[k] = (SC_ZERO + (m % SC_B10)) as u8; m = m / SC_B10; k = k + 1 } 99 var i: i64 = 0 100 while i < k { d[p] = t[k-1-i]; p = p + 1; i = i + 1 } 101 d[p] = 0 as u8 102 return p 103} 104 105func sc_path(d: *u8, rel: *u8) -> *u8 { 106 var o: i64 = sc_cat(d, 0, g_root) 107 d[o] = SC_SLASH as u8 108 o = o + 1 109 o = sc_cat(d, o, rel) 110 return d 111} 112 113func sc_readf(rel: *u8, cap: i64) -> *u8 { 114 let pb: *u8 = sys_mmap(SC_PATHCAP) 115 let pp: *u8 = sc_path(pb, rel) 116 let buf: *u8 = sys_mmap(cap) 117 g_rn = 0 118 let fd: i64 = sys_openat_rd(pp) 119 if fd < 0 { return buf } 120 var t: i64 = 0 121 var done: i64 = 0 122 while done == 0 { 123 let want: i64 = cap - 8 - t 124 let r: i64 = sys_read(fd, buf + t, want) 125 if r <= 0 { done = 1 } else { t = t + r; if t >= cap - 8 { done = 1; g_hitcap = 1 } } 126 } 127 sys_close(fd) 128 g_rn = t 129 return buf 130} 131 132func sc_le(b: *u8, i: i64, n: i64) -> i64 { 133 var j: i64 = i 134 var d: i64 = 0 135 while d == 0 { 136 if j >= n { d = 1 } else { if b[j] == (SC_NL as u8) { d = 1 } else { j = j + 1 } } 137 } 138 return j 139} 140 141func sc_col(b: *u8, ls: i64, le: i64, want: i64, sp: *i64) -> i64 { 142 var c: i64 = 0 143 var s: i64 = ls 144 var j: i64 = ls 145 var fnd: i64 = 0 146 var d: i64 = 0 147 while d == 0 { 148 var hit: i64 = 0 149 if j >= le { hit = 1 } else { if b[j] == (SC_TAB as u8) { hit = 1 } } 150 if hit == 1 { 151 if c == want { sp[0] = s; sp[1] = j; fnd = 1; d = 1 } else { c = c + 1; s = j + 1; if j >= le { d = 1 } else { j = j + 1 } } 152 } else { j = j + 1 } 153 } 154 return fnd 155} 156 157func sc_span_lit(b: *u8, s: i64, e: i64, lit: *u8) -> i64 { 158 let n: i64 = sc_len(lit) 159 if e - s != n { return 0 } 160 var i: i64 = 0 161 while i < n { let bi: i64 = s + i; if b[bi] != lit[i] { return 0 } i = i + 1 } 162 return 1 163} 164 165func sc_cpspan(b: *u8, sp: *i64) -> *u8 { 166 var i: i64 = sp[0] 167 var k: i64 = 0 168 while i < sp[1] { g_scr[k] = b[i]; k = k + 1; i = i + 1 } 169 g_scr[k] = 0 as u8 170 return g_scr 171} 172 173func sc_cpspan2(b: *u8, sp: *i64) -> *u8 { 174 var i: i64 = sp[0] 175 var k: i64 = 0 176 while i < sp[1] { g_scr2[k] = b[i]; k = k + 1; i = i + 1 } 177 g_scr2[k] = 0 as u8 178 return g_scr2 179} 180 181func sc_name_in(b: *u8, n: i64, name: *u8, col: i64) -> i64 { 182 var i: i64 = 0 183 var fnd: i64 = 0 184 while i < n { 185 let le: i64 = sc_le(b, i, n) 186 var skip: i64 = 0 187 if le <= i { skip = 1 } else { if b[i] == (SC_HASH as u8) { skip = 1 } } 188 if skip == 0 { 189 if fnd == 0 { 190 if sc_col(b, i, le, col, g_sp) == 1 { if sc_span_lit(b, g_sp[0], g_sp[1], name) == 1 { fnd = 1 } } 191 } 192 } 193 i = le + 1 194 } 195 return fnd 196} 197 198func sc_has_new(b: *u8, sp: *i64) -> i64 { 199 var i: i64 = sp[0] 200 while i + SC_NEWLEN <= sp[1] { 201 if b[i] == (SC_DOT as u8) { if b[i+1] == (SC_LC_N as u8) { if b[i+2] == (SC_LC_E as u8) { if b[i+3] == (SC_LC_W as u8) { return 1 } } } } 202 i = i + 1 203 } 204 return 0 205} 206 207func sc_exists(p: *u8) -> i64 { 208 let sb: *u8 = sys_mmap(SC_STATBUF) 209 let r: i64 = sys_fstatat(p, sb) 210 if r == 0 { return 1 } 211 return 0 212} 213 214// emit=1 prints each offending NAME to stdout instead of only counting it. 215// WHY (2026-08-03, debt 1785773047): this class grew 40 -> 512 in 13 days and the only interface to it was a 216// COUNT. `nx_shelltool glob '*.elf.new' .` BUDGET-EXCEEDS before finishing the root walk, and the log stores 217// counts only -- so the estate could see the number and never the members. A DETECTOR THAT COUNTS A CLASS IT 218// CANNOT ENUMERATE HANDS YOU A NUMBER YOU CANNOT ACT ON. Same one-level walk, same predicate, so the list can 219// never disagree with the count it reports. 220func sc_scan_new(emit: i64) -> i64 { 221 let fd: i64 = sys_openat_rd(g_root) 222 if fd < 0 { return 0 } 223 let db: *u8 = sys_mmap(SC_DIRCAP) 224 var cnt: i64 = 0 225 var done: i64 = 0 226 while done == 0 { 227 let nr: i64 = sys_getdents64(fd, db, SC_DIRCAP) 228 if nr <= 0 { done = 1 } else { 229 var p: i64 = 0 230 while p < nr { 231 let rlo: i64 = db[p+16] as i64 232 let rhi: i64 = db[p+17] as i64 233 let rl: i64 = rlo + rhi * SC_B256 234 let ns: i64 = p + 19 235 var ne: i64 = ns 236 while db[ne] != (0 as u8) { ne = ne + 1 } 237 if ne - ns >= SC_NEWLEN { if db[ne-4] == (SC_DOT as u8) { if db[ne-3] == (SC_LC_N as u8) { if db[ne-2] == (SC_LC_E as u8) { if db[ne-1] == (SC_LC_W as u8) { cnt = cnt + 1; if emit == 1 { sys_write(1, (((db as i64) + ns) as *u8), ne - ns); sys_write(1, "\n" as *u8, 1) } } } } } } 238 if rl <= 0 { p = nr } else { p = p + rl } 239 } 240 } 241 } 242 sys_close(fd) 243 return cnt 244} 245 246func sc_atoi_span(b: *u8, sp: *i64) -> i64 { 247 var v: i64 = 0 248 var i: i64 = sp[0] 249 while i < sp[1] { let ch: i64 = b[i] as i64; if ch >= SC_ZERO { if ch <= SC_NINE { v = v * SC_B10 + (ch - SC_ZERO) } } i = i + 1 } 250 return v 251} 252 253func sc_last_num_after(b: *u8, pat: *u8) -> i64 { 254 let n: i64 = g_rn 255 let pl: i64 = sc_len(pat) 256 var best: i64 = 0 - 1 257 var i: i64 = 0 258 while i + pl <= n { 259 var k: i64 = 0 260 var ok: i64 = 1 261 while k < pl { let bi: i64 = i + k; if b[bi] != pat[k] { ok = 0; k = pl } else { k = k + 1 } } 262 if ok == 1 { best = i + pl } 263 i = i + 1 264 } 265 if best < 0 { return 0 - 1 } 266 var v: i64 = 0 267 var j: i64 = best 268 var any: i64 = 0 269 var d: i64 = 0 270 while d == 0 { 271 let ch: i64 = b[j] as i64 272 var isd: i64 = 0 273 if ch >= SC_ZERO { if ch <= SC_NINE { isd = 1 } } 274 if isd == 1 { v = v * SC_B10 + (ch - SC_ZERO); any = 1; j = j + 1 } else { d = 1 } 275 } 276 if any == 0 { return 0 - 1 } 277 return v 278} 279 280func sc_l003(b: *u8) -> i64 { 281 let n: i64 = g_rn 282 var best: i64 = 0 - 1 283 var i: i64 = 0 284 while i < n { 285 let le: i64 = sc_le(b, i, n) 286 if sc_col(b, i, le, 2, g_sp) == 1 { 287 if sc_span_lit(b, g_sp[0], g_sp[1], "L003") == 1 { 288 if sc_col(b, i, le, 3, g_sp) == 1 { 289 if sc_span_lit(b, g_sp[0], g_sp[1], "unregistered") == 1 { 290 if sc_col(b, i, le, 4, g_sp) == 1 { best = sc_atoi_span(b, g_sp) } 291 } 292 } 293 } 294 } 295 i = le + 1 296 } 297 return best 298} 299 300func sc_scan() -> i64 { 301 g_hitcap = 0 302 g_allow = sc_readf("tool_allowlist.conf", SC_BUFCAP) 303 g_an = g_rn 304 g_schema = sc_readf("knowledge/tool_schemas.conf", SC_BUFCAP) 305 g_sn = g_rn 306 g_atlas = sc_readf("knowledge/registry/atlas_catalog.tsv", SC_BUFCAP) 307 g_atn = g_rn 308 g_c_allow = 0 309 g_c_schema = 0 310 g_c_noschema = 0 311 g_c_staleschema = 0 312 g_c_stagedref = 0 313 g_c_missingbin = 0 314 g_c_straynew = 0 315 g_c_dupsrc = 0 316 g_c_unreg = 0 317 g_c_noatlas = 0 318 var i: i64 = 0 319 while i < g_an { 320 let le: i64 = sc_le(g_allow, i, g_an) 321 var skip: i64 = 0 322 if le <= i { skip = 1 } else { if g_allow[i] == (SC_HASH as u8) { skip = 1 } } 323 if skip == 0 { 324 if sc_col(g_allow, i, le, 0, g_sp) == 1 { 325 if g_sp[1] > g_sp[0] { 326 g_c_allow = g_c_allow + 1 327 let nm: *u8 = sc_cpspan(g_allow, g_sp) 328 if sc_name_in(g_schema, g_sn, nm, 0) == 0 { g_c_noschema = g_c_noschema + 1 } 329 if sc_name_in(g_atlas, g_atn, nm, 1) == 0 { g_c_noatlas = g_c_noatlas + 1 } 330 if sc_col(g_allow, i, le, 1, g_sp) == 1 { 331 if sc_has_new(g_allow, g_sp) == 1 { g_c_stagedref = g_c_stagedref + 1 } else { 332 let pp: *u8 = sc_cpspan2(g_allow, g_sp) 333 if sc_exists(pp) == 0 { g_c_missingbin = g_c_missingbin + 1 } 334 } 335 } 336 } 337 } 338 } 339 i = le + 1 340 } 341 var j: i64 = 0 342 while j < g_sn { 343 let le2: i64 = sc_le(g_schema, j, g_sn) 344 var skip2: i64 = 0 345 if le2 <= j { skip2 = 1 } else { if g_schema[j] == (SC_HASH as u8) { skip2 = 1 } } 346 if skip2 == 0 { 347 if sc_col(g_schema, j, le2, 0, g_sp) == 1 { 348 if g_sp[1] > g_sp[0] { 349 g_c_schema = g_c_schema + 1 350 let nm2: *u8 = sc_cpspan(g_schema, g_sp) 351 if sc_name_in(g_allow, g_an, nm2, 0) == 0 { g_c_staleschema = g_c_staleschema + 1 } 352 } 353 } 354 } 355 j = le2 + 1 356 } 357 g_c_straynew = sc_scan_new(0) 358 let db: *u8 = sc_readf("knowledge/status/dup_source.log", SC_LOGCAP) 359 g_c_dupsrc = sc_last_num_after(db, "basenames found: ") 360 let wb: *u8 = sc_readf("knowledge/status/law_warden.jrnl", SC_LOGCAP) 361 g_c_unreg = sc_l003(wb) 362 return 0 363} 364 365func sc_append(b: *u8, n: i64) -> i64 { 366 let pb: *u8 = sys_mmap(SC_PATHCAP) 367 let lp: *u8 = sc_path(pb, "knowledge/status/shipcheck.log") 368 let fd: i64 = sys_openat_append(lp, SC_MODE_F) 369 if fd < 0 { return 0 } 370 sys_write(fd, b, n) 371 sys_close(fd) 372 return 1 373} 374 375func sc_emit(verb: *u8) -> i64 { 376 let ts: *i64 = sys_mmap(16) as *i64 377 sys_clock_gettime_real(ts) 378 let ep: i64 = ts[0] 379 let ob: *u8 = sys_mmap(SC_OUTCAP) 380 var o: i64 = 0 381 o = sc_cat(ob, o, "SHIPCHECK epoch=" as *u8) 382 o = sc_catn(ob, o, ep) 383 o = sc_cat(ob, o, " verb=" as *u8) 384 o = sc_cat(ob, o, verb) 385 o = sc_cat(ob, o, " allow=" as *u8) 386 o = sc_catn(ob, o, g_c_allow) 387 o = sc_cat(ob, o, " schema=" as *u8) 388 o = sc_catn(ob, o, g_c_schema) 389 o = sc_cat(ob, o, " noschema=" as *u8) 390 o = sc_catn(ob, o, g_c_noschema) 391 o = sc_cat(ob, o, " staleschema=" as *u8) 392 o = sc_catn(ob, o, g_c_staleschema) 393 o = sc_cat(ob, o, " stagedref=" as *u8) 394 o = sc_catn(ob, o, g_c_stagedref) 395 o = sc_cat(ob, o, " missingbin=" as *u8) 396 o = sc_catn(ob, o, g_c_missingbin) 397 o = sc_cat(ob, o, " straynew=" as *u8) 398 o = sc_catn(ob, o, g_c_straynew) 399 o = sc_cat(ob, o, " dupsrc=" as *u8) 400 o = sc_catn(ob, o, g_c_dupsrc) 401 o = sc_cat(ob, o, " unreg_l003=" as *u8) 402 o = sc_catn(ob, o, g_c_unreg) 403 o = sc_cat(ob, o, " noatlas=" as *u8) 404 o = sc_catn(ob, o, g_c_noatlas) 405 o = sc_cat(ob, o, " frowjoin=-1 capped=" as *u8) 406 o = sc_catn(ob, o, g_hitcap) 407 var bad: i64 = 0 408 bad = g_c_noschema + g_c_staleschema + g_c_stagedref + g_c_missingbin + g_c_straynew + g_c_noatlas 409 if bad > 0 { o = sc_cat(ob, o, " verdict=RED" as *u8) } else { o = sc_cat(ob, o, " verdict=GREEN" as *u8) } 410 ob[o] = SC_NL as u8 411 o = o + 1 412 sys_write(1, ob, o) 413 sc_append(ob, o) 414 if bad > 0 { return SC_EXITRED } 415 return 0 416} 417 418func sc_allow_path(name: *u8, outp: *u8) -> i64 { 419 var i: i64 = 0 420 var fnd: i64 = 0 421 while i < g_an { 422 let le: i64 = sc_le(g_allow, i, g_an) 423 var skip: i64 = 0 424 if le <= i { skip = 1 } else { if g_allow[i] == (SC_HASH as u8) { skip = 1 } } 425 if skip == 0 { 426 if fnd == 0 { 427 if sc_col(g_allow, i, le, 0, g_sp) == 1 { 428 if sc_span_lit(g_allow, g_sp[0], g_sp[1], name) == 1 { 429 if sc_col(g_allow, i, le, 1, g_sp) == 1 { 430 var k: i64 = 0 431 var z: i64 = g_sp[0] 432 while z < g_sp[1] { outp[k] = g_allow[z]; k = k + 1; z = z + 1 } 433 outp[k] = 0 as u8 434 fnd = 1 435 } 436 } 437 } 438 } 439 } 440 i = le + 1 441 } 442 return fnd 443} 444 445func sc_spawn_filer(fpath: *u8, desc: *u8) -> i64 { 446 let sevs: *u8 = sys_mmap(8) 447 let so: i64 = sc_catn(sevs, 0, g_sev) 448 let av: *i64 = sys_mmap(64) as *i64 449 av[0] = fpath as i64 450 av[1] = "add" as *u8 as i64 451 av[2] = sevs as i64 452 av[3] = "shipcomplete" as *u8 as i64 453 av[4] = desc as i64 454 av[5] = 0 455 let env: *i64 = sys_mmap(8) as *i64 456 env[0] = 0 457 let pid: i64 = sys_fork() 458 if pid == 0 { sys_execve(fpath, av, env); sys_exit_group(SC_EXEFAIL) } 459 let st: *i64 = sys_mmap(16) as *i64 460 st[0] = 0 461 sys_wait4(pid, st, 0) 462 let raw: i64 = st[0] 463 let code: i64 = (raw / SC_B256) % SC_B256 464 return code 465} 466 467func sc_file_cls(fpath: *u8, tail: *u8) -> i64 { 468 let desc: *u8 = sys_mmap(SC_DESCCAP) 469 var o: i64 = 0 470 o = sc_cat(desc, 0, "SHIPCOMPLETE-ORPHAN " as *u8) 471 o = sc_cat(desc, o, tail) 472 let rc: i64 = sc_spawn_filer(fpath, desc) 473 let rb: *u8 = sys_mmap(SC_PATHCAP) 474 var ro: i64 = 0 475 ro = sc_cat(rb, 0, "FILED class=" as *u8) 476 var i: i64 = 0 477 var d: i64 = 0 478 while d == 0 { 479 let ch: i64 = tail[i] as i64 480 if ch == 0 { d = 1 } else { if ch == SC_COLON { d = 1 } else { rb[ro] = tail[i]; ro = ro + 1; i = i + 1 } } 481 } 482 ro = sc_cat(rb, ro, " exit=" as *u8) 483 ro = sc_catn(rb, ro, rc) 484 rb[ro] = SC_NL as u8 485 ro = ro + 1 486 sys_write(1, rb, ro) 487 sc_append(rb, ro) 488 return rc 489} 490 491func sc_file(filer: *u8) -> i64 { 492 let fpath: *u8 = sys_mmap(SC_PATHCAP) 493 let fok: i64 = sc_allow_path(filer, fpath) 494 if fok == 0 { 495 let eb: *u8 = sys_mmap(SC_PATHCAP) 496 var eo: i64 = 0 497 eo = sc_cat(eb, 0, "SHIPCHECK-FILE filer-unresolved" as *u8) 498 eb[eo] = SC_NL as u8 499 eo = eo + 1 500 sys_write(1, eb, eo) 501 sc_append(eb, eo) 502 return 1 503 } 504 if g_c_stagedref > 0 { g_sev = SC_SEV_STAGEDREF; sc_file_cls(fpath, "stagedref: registered MCP tools whose tool_allowlist.conf binary path points at a staged .new artifact (registered-but-never-promoted) -- promote or withdraw each; live counts in knowledge/status/shipcheck.log (nx_shipcheck)" as *u8) } 505 if g_c_missingbin > 0 { g_sev = SC_SEV_MISSINGBIN; sc_file_cls(fpath, "missingbin: registered MCP tools whose allowlisted binary is ABSENT on disk (tools-call would exec-fail) -- restore or deregister; live counts in knowledge/status/shipcheck.log (nx_shipcheck)" as *u8) } 506 if g_c_noschema > 0 { g_sev = SC_SEV_NOSCHEMA; sc_file_cls(fpath, "noschema: tool registry rows with NO schema row in knowledge/tool_schemas.conf (agents fly blind on safety and verbs) -- add schema-bridge rows; live counts in knowledge/status/shipcheck.log (nx_shipcheck)" as *u8) } 507 if g_c_staleschema > 0 { g_sev = SC_SEV_STALESCHEMA; sc_file_cls(fpath, "staleschema: tool_schemas.conf rows whose tool is NOT in tool_allowlist.conf (ghost schema, nx_seat-class staleness) -- reconcile or retire each row; live counts in knowledge/status/shipcheck.log (nx_shipcheck)" as *u8) } 508 if g_c_straynew > 0 { g_sev = SC_SEV_STRAYNEW; sc_file_cls(fpath, "straynew: stranded staged .new artifacts in the deploy root (never promoted, never cleaned) -- promote or evict via nx_evict; live counts in knowledge/status/shipcheck.log (nx_shipcheck)" as *u8) } 509 if g_c_noatlas > 0 { g_sev = SC_SEV_NOATLAS; sc_file_cls(fpath, "noatlas: registered MCP tools absent from the atlas recombination catalog knowledge/registry/atlas_catalog.tsv (invisible to discovery and recombination) -- register via nx_atlas_catseed; live counts in knowledge/status/shipcheck.log (nx_shipcheck)" as *u8) } 510 return 0 511} 512 513func main(argc: i64, argv: *i64) -> i64 { 514 g_scr = sys_mmap(SC_PATHCAP) 515 g_scr2 = sys_mmap(SC_PATHCAP) 516 g_sp = sys_mmap(16) as *i64 517 g_root = "." as *u8 518 var verb: *u8 = "scan" as *u8 519 if argc >= 2 { verb = argv[1] as *u8 } 520 if argc >= 3 { g_root = argv[2] as *u8 } 521 var filer: *u8 = "nx_debt" as *u8 522 if argc >= 4 { filer = argv[3] as *u8 } 523 // listnew: PRINT the straynew members (the class this organ could previously only count). Deliberately 524 // BEFORE sc_scan() so the listing costs one directory walk and nothing else, and returns the COUNT as its 525 // exit code -- so a caller can pipe the names AND branch on how many there were. 526 if sc_span_lit(verb, 0, sc_len(verb), "listnew" as *u8) == 1 { 527 let ln: i64 = sc_scan_new(1) 528 return ln 529 } 530 sc_scan() 531 let rc: i64 = sc_emit(verb) 532 var dofile: i64 = 0 533 if sc_span_lit(verb, 0, sc_len(verb), "beat" as *u8) == 1 { dofile = 1 } 534 if sc_span_lit(verb, 0, sc_len(verb), "file" as *u8) == 1 { dofile = 1 } 535 if dofile == 1 { sc_file(filer) } 536 return rc 537}