code wiki / _hdl_build / nx_toolhealth.nx

nx_toolhealth.nx source

↩ module page · 993 lines · 47700 B

1// nx_toolhealth.nx -- FOUNDATION CENSUS over the REGISTERED-TOOL POPULATION (lane D, 2026-08-20). 2// The operator named three symptoms in one sentence -- "broken tools and duplicate tools and things like 3// the research only are half capable" -- and the estate counted them in separate censuses that never 4// adjudicated as ONE foundation. This organ measures the two that had no instrument at all, over EVERY 5// row of tool_allowlist.conf (the GREEN execution allowlist == the registered-tool registry), dedupes 6// REFERENCES to SUBJECTS, and prints a partition that must SUM. 7// BROKEN, per SUBJECT, one class each and the four sum to the subject count: 8// PHANTOM no elf anywhere AND no .nx -- the CALLER must be fixed or deleted; it can never 9// be built, and hiding it in a build queue guarantees the queue never finishes. 10// MISSING-BUILDABLE no elf, source exists -- a build. 11// BINARY-NO-SOURCE elf present, no .nx -- often code that SHIPS INSIDE ANOTHER ARTIFACT. Its own 12// bucket on purpose: a stat-based catalogue reads this as "build it", which is a 13// harmful work order, so it is NEVER folded into MISSING-BUILDABLE. 14// OK elf and source both present. 15// UNREACHABLE is a SEPARATE AXIS, never a partition member -- a subject can be OK and non-GREEN at 16// once, so folding it in would silently break the reconciliation. COUNT ONLY (lane A owns the repair). 17// HALF-CAPABLE: a verb DECLARED in the SERVED call grammar with no dispatch branch in the source. The 18// served grammar is resolved exactly as nx_tools_api resolves it -- authored tool_schemas.conf col8 19// first, derived tool_grammar.conf second -- so this measures the contract an AGENT actually reads. 20// HOW A VERB IS JUDGED IMPLEMENTED: its name appears in the source as a QUOTED STRING LITERAL (the 21// byte sequence quote-verb-quote). That is what every dispatch in this estate compiles to, and a usage 22// line -- which is a COMMENT, or a single long "usage: a | b" literal -- can never satisfy it. 23// THE DETECTOR IS DELIBERATELY WRONG IN THE DIRECTION OF NOT ACCUSING. Four abstentions, each its own 24// bucket, because a false positive teaches everyone to ignore the detector: 25// PINNED the allowlist row carries a 4th column, so the registry supplies argv and the caller's is 26// DISCARDED. Its grammar names no callable verb; it can have no dead verb by construction. 27// NO-GRAMMAR neither grammar file has a row -- an agent has NO contract to read. A real gap, listed. 28// POSITIONAL-ONLY a contract exists and declares no VERB. NOT a defect -- and NOT the same bucket 29// as NO-GRAMMAR, whose remedy is the opposite. Merging them read 618 of 959. 30// (this bullet is indented FOUR spaces on purpose: at 2-3 spaces the grammar harvester 31// reads a comment carrying < or [ as a USAGE LINE, so this very explanation became this 32// organ's declared call grammar and the census then accused ITSELF of a dead verb named 33// POSITIONAL-ONLY. A TOOL WHOSE INPUT IS ITS OWN DOCUMENTATION MUST OBEY THE DOCUMENT 34// CONVENTION IT MEASURES -- caught by the ratchet, not by review.) 35// UNDECIDABLE the grammar declares 2+ verbs and NOT ONE of them appears as a literal => this organ 36// cannot see this subject's dispatch mechanism at all. Reporting N dead verbs there would 37// be a confident wrong answer; abstaining names it for a human instead. 38// RATCHET: the baseline is a SET OF NAMES, never a count -- a count-only ratchet on a shared tree 39// reports a regression without saying whose. Removals ratchet down automatically; ADDITIONS keep firing 40// until fixed or explicitly adopted with `accept`. 41// nx_toolhealth census [allowlist] [schemas] [grammar] [log] [baseline] [srcroot-a] [srcroot-b] -> JSON census + worklist 42// nx_toolhealth verbscan <grammar-file> <source.nx> [selfname] -> declared/implemented/DEAD, one subject 43// nx_toolhealth ratchet [baseline] [log] -> NEW offenders NAMED against the stored name set 44// nx_toolhealth accept [baseline] [log] -> adopt the current offender set as the new baseline 45// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 46import "nx_syscalls.nx" 47import "nx_estr.nx" 48 49// sized: the registry is ~1.2k rows today; REFUSE above this rather than publish a silent prefix 50const TH_ROWCAP: i64 = 8192 51// derived: subjects <= rows by construction (many names can share one elf) 52const TH_SUBJCAP: i64 = 8192 53// sized: the register API sanitizes tool names to <= 120 bytes 54const TH_NAMECAP: i64 = 128 55// sized: absolute NAS paths sit well inside this 56const TH_PATHCAP: i64 = 1024 57// sized: matches nx_toolgrammar's joined-grammar cap plus the authored col8 headroom 58const TH_GRAMCAP: i64 = 2048 59// derived: the longest real verb measured in the corpus is well under this 60const TH_VERBCAP: i64 = 48 61// declared: at most this many distinct verbs parsed from one grammar 62const TH_MAXVERBS: i64 = 48 63// sized: struct stat is 144 bytes on x86_64; a round envelope with headroom 64const TH_STATBUF: i64 = 256 65// sized: one emitted worklist row 66const TH_LINEBUF: i64 = 4096 67// the two verbs a grammar must declare before an all-absent result means UNDECIDABLE rather than dead 68const TH_UNDECIDABLE_MIN: i64 = 2 69const TH_MODE_FILE: i64 = 0x1a4 70const TH_MODE_DIR: i64 = 0x1ed 71const TH_EXIT_OK: i64 = 0 72const TH_EXIT_REGRESSED: i64 = 1 73const TH_EXIT_USAGE: i64 = 2 74const TH_EXIT_REFUSED: i64 = 4 75 76const TH_TAB: i64 = 9 77const TH_NL: i64 = 10 78const TH_SPACE: i64 = 32 79const TH_QUOTE: i64 = 34 80const TH_HASH: i64 = 35 81const TH_PIPE: i64 = 124 82const TH_SLASH: i64 = 47 83const TH_LT: i64 = 60 84const TH_GT: i64 = 62 85const TH_LBRACK: i64 = 91 86const TH_LPAREN: i64 = 40 87const TH_RPAREN: i64 = 41 88const TH_RBRACK: i64 = 93 89const TH_EQ: i64 = 61 90const TH_DASH: i64 = 45 91const TH_UNDER: i64 = 95 92const TH_DIGIT0: i64 = 48 93const TH_DIGIT9: i64 = 57 94const TH_UPA: i64 = 65 95const TH_UPZ: i64 = 90 96const TH_LOA: i64 = 97 97const TH_LOZ: i64 = 122 98 99const TH_DEF_ALLOW: *u8 = "tool_allowlist.conf" 100const TH_DEF_SCHEMAS: *u8 = "knowledge/tool_schemas.conf" 101const TH_DEF_GRAMMAR: *u8 = "knowledge/tool_grammar.conf" 102const TH_DEF_LOG: *u8 = "knowledge/status/toolhealth.log" 103const TH_DEF_BASE: *u8 = "knowledge/status/toolhealth_ratchet.conf" 104const TH_SRC_A: *u8 = "buildroot/runtime/_hdl_build/" 105const TH_SRC_B: *u8 = "buildroot/runtime/" 106const TH_STATUS_DIR: *u8 = "knowledge/status" 107 108// class codes, kept as named consts so a bucket can never be spelled twice 109const TH_CLS_OK: i64 = 0 110const TH_CLS_MISSING_BUILDABLE: i64 = 1 111const TH_CLS_PHANTOM: i64 = 2 112const TH_CLS_BINARY_NO_SOURCE: i64 = 3 113// half-capable states 114const TH_HC_CLEAN: i64 = 0 115const TH_HC_DEAD: i64 = 1 116const TH_HC_PINNED: i64 = 2 117const TH_HC_NOGRAMMAR: i64 = 3 118const TH_HC_UNDECIDABLE: i64 = 4 119const TH_HC_NOSOURCE: i64 = 5 120const TH_HC_POSITIONAL: i64 = 6 121 122static TH_TRUNCATED: i64 = 0 123 124func thw(s: *u8) -> i64 { es_puts(s); return 0 } 125func thn(v: i64) -> i64 { es_putn(v); return 0 } 126 127func th_streq(a: *u8, al: i64, b: *u8, bl: i64) -> i64 { 128 if al != bl { return 0 } 129 var i: i64 = 0 130 while i < al { if a[i] != b[i] { return 0 } i = i + 1 } 131 return 1 132} 133 134func th_exists(path: *u8) -> i64 { 135 let sb: *u8 = sys_mmap(TH_STATBUF) 136 if sys_fstatat(path, sb) == 0 { return 1 } 137 return 0 138} 139 140// copy TAB-separated field `idx` (0-based) of the line [ls,le) into out; returns length (0 = absent). 141func th_field(buf: *u8, ls: i64, le: i64, idx: i64, out: *u8, cap: i64) -> i64 { 142 var f: i64 = 0 143 var p: i64 = ls 144 while f < idx { 145 var go: i64 = 1 146 while go == 1 { 147 if p >= le { go = 0 } else { 148 if buf[p] == (TH_TAB as u8) { go = 0 } else { p = p + 1 } 149 } 150 } 151 if p >= le { out[0] = 0 as u8; return 0 } 152 p = p + 1 153 f = f + 1 154 } 155 var o: i64 = 0 156 var g2: i64 = 1 157 while g2 == 1 { 158 if p >= le { g2 = 0 } else { 159 if buf[p] == (TH_TAB as u8) { g2 = 0 } else { 160 if o < cap - 1 { out[o] = buf[p]; o = o + 1 } 161 p = p + 1 162 } 163 } 164 } 165 out[o] = 0 as u8 166 return o 167} 168 169func th_count_fields(buf: *u8, ls: i64, le: i64) -> i64 { 170 var c: i64 = 1 171 var p: i64 = ls 172 while p < le { if buf[p] == (TH_TAB as u8) { c = c + 1 } p = p + 1 } 173 return c 174} 175 176func th_ends(s: *u8, sl: i64, suf: *u8, fl: i64) -> i64 { 177 if sl < fl { return 0 } 178 var i: i64 = 0 179 while i < fl { if s[sl-fl+i] != suf[i] { return 0 } i = i + 1 } 180 return 1 181} 182 183// stem = elf basename with any staged/built suffix removed (the nx_toolgrammar ladder, reused not retyped) 184func th_stem(elf: *u8, el: i64, out: *u8, cap: i64) -> i64 { 185 var bs: i64 = 0 186 var k: i64 = 0 187 while k < el { if elf[k] == (TH_SLASH as u8) { bs = k + 1 } k = k + 1 } 188 var sl: i64 = el - bs 189 let base: *u8 = ((elf as i64) + bs) as *u8 190 if th_ends(base, sl, ".sov.elf.new" as *u8, 12) == 1 { sl = sl - 12 } else { 191 if th_ends(base, sl, ".elf.new" as *u8, 8) == 1 { sl = sl - 8 } else { 192 if th_ends(base, sl, ".sov.elf" as *u8, 8) == 1 { sl = sl - 8 } else { 193 if th_ends(base, sl, ".elf" as *u8, 4) == 1 { sl = sl - 4 } else { 194 if th_ends(base, sl, ".new" as *u8, 4) == 1 { sl = sl - 4 } 195 } 196 } 197 } 198 } 199 var o: i64 = 0 200 while o < sl { if o < cap - 1 { out[o] = base[o] } o = o + 1 } 201 if o > cap - 1 { o = cap - 1 } 202 out[o] = 0 as u8 203 return o 204} 205 206// find the row whose field 0 equals key; copy field `gidx` into out. returns length, 0 = no row/empty. 207func th_lookup(buf: *u8, n: i64, key: *u8, kl: i64, gidx: i64, out: *u8, cap: i64) -> i64 { 208 var i: i64 = 0 209 while i < n { 210 var le: i64 = i 211 var sc: i64 = 1 212 while sc == 1 { if le >= n { sc = 0 } else { if buf[le] == (TH_NL as u8) { sc = 0 } else { le = le + 1 } } } 213 var hit: i64 = 0 214 if le > i { 215 if buf[i] != (TH_HASH as u8) { 216 if le - i > kl { 217 if buf[i+kl] == (TH_TAB as u8) { 218 var j: i64 = 0 219 var m: i64 = 1 220 while j < kl { if buf[i+j] != key[j] { m = 0; j = kl } else { j = j + 1 } } 221 hit = m 222 } 223 } 224 } 225 } 226 if hit == 1 { return th_field(buf, i, le, gidx, out, cap) } 227 i = le + 1 228 } 229 out[0] = 0 as u8 230 return 0 231} 232 233func th_is_wordbyte(c: i64) -> i64 { 234 if c >= TH_LOA { if c <= TH_LOZ { return 1 } } 235 if c >= TH_UPA { if c <= TH_UPZ { return 1 } } 236 if c >= TH_DIGIT0 { if c <= TH_DIGIT9 { return 1 } } 237 if c == TH_UNDER { return 1 } 238 if c == TH_DASH { return 1 } 239 return 0 240} 241 242func th_is_alpha(c: i64) -> i64 { 243 if c >= TH_LOA { if c <= TH_LOZ { return 1 } } 244 if c >= TH_UPA { if c <= TH_UPZ { return 1 } } 245 return 0 246} 247 248// IS THIS TOKEN THE NAME OF SOME OTHER REGISTERED TOOL? Then it is a CROSS-REFERENCE in prose, not a 249// verb -- no organ in this estate dispatches on a sibling organ's name. `names` is the allowlist buffer 250// (field 0 of each row is a tool name); pass nn=0 to disable the test. 251// MEASURED WHY THIS MATTERS FAR MORE THAN ONE BAD ROW: the tool-name token is ALSO the token most likely 252// to appear in the source as a literal, because every banner prints the organ's own name. So it scores 253// as IMPLEMENTED, which lifts implemented above zero, which DISABLES the DISPATCH-UNDECIDABLE abstention 254// for the whole subject -- and the real verbs beside it get reported dead. nx_lease was exactly this: 255// 4 genuine verbs accused because a 5th false one made the abstention look unnecessary. 256// A FALSE POSITIVE THAT LOOKS IMPLEMENTED DOES NOT ADD ONE BAD ROW, IT SWITCHES OFF THE SAFETY NET. 257func th_is_toolname(names: *u8, nn: i64, tok: *u8, tl: i64) -> i64 { 258 if nn <= 0 { return 0 } 259 var i: i64 = 0 260 while i < nn { 261 var le: i64 = i 262 var sc: i64 = 1 263 while sc == 1 { if le >= nn { sc = 0 } else { if names[le] == (TH_NL as u8) { sc = 0 } else { le = le + 1 } } } 264 if le - i > tl { 265 if names[i+tl] == (TH_TAB as u8) { 266 var j: i64 = 0 267 var m: i64 = 1 268 while j < tl { if names[i+j] != tok[j] { m = 0; j = tl } else { j = j + 1 } } 269 if m == 1 { return 1 } 270 } 271 } 272 i = le + 1 273 } 274 return 0 275} 276 277// Extract VERB tokens from a SERVED grammar. Four rules, every one earned by a measured false positive 278// on the live corpus (2026-08-20: 121 accusations of which roughly 49 were these four shapes): 279// F1 ALTERNATIVES SPLIT ON PIPE AT BRACKET DEPTH ZERO ONLY. `build [all|recordings|movies|books]` is 280// ONE alternative enumerating its ARGUMENT, not five verbs. Splitting blind invented recordings / 281// movies / books / stale for nx_media_inventory, and the same shape for footcheck, sourcing_path, 282// capaxes_derive and drv_proto_emit. 283// F2 A TOKEN THAT NAMES ANOTHER REGISTERED TOOL IS PROSE (see th_is_toolname above). 284// F3 A TOKEN FOLLOWED BY AN EQUALS SIGN IS A DESCRIPTION KEY, NOT A VERB. Live shape, nx_netobs: 285// `no-arg = clock beat (sample+page+heartbeat) | sample | page | ...` -- the real verbs follow. 286// F4 A ONE-ALTERNATIVE GRAMMAR CARRYING NO ARGUMENT MARKER AT ALL IS PROSE, NOT A CONTRACT. The served 287// grammar of 27 finance/legal gates is the literal string `no args`, and a blind first-token read 288// turned every one of them into a dead verb named "no". 289// The tool's own name leading an alternative is skipped, and the SECOND token is then the verb. 290// verbs is a flat TH_MAXVERBS * TH_VERBCAP buffer; APPENDS from nv0 and returns the new count, so one 291// subject can union the verbs of every registered name that points at it. 292func th_verbs(gram: *u8, gl: i64, selfname: *u8, snl: i64, names: *u8, nn: i64, verbs: *u8, vlen: *i64, nv0: i64) -> i64 { 293 var nv: i64 = nv0 294 // ---- F4 pre-pass: is there an argument marker anywhere, and how many depth-0 alternatives? 295 var hasarg: i64 = 0 296 var alts: i64 = 1 297 var d0: i64 = 0 298 var z: i64 = 0 299 while z < gl { 300 let cz: i64 = gram[z] as i64 301 if cz == TH_LT { hasarg = 1; d0 = d0 + 1 } 302 if cz == TH_LBRACK { hasarg = 1; d0 = d0 + 1 } 303 if cz == TH_LPAREN { d0 = d0 + 1 } 304 if cz == TH_GT { d0 = d0 - 1 } 305 if cz == TH_RBRACK { d0 = d0 - 1 } 306 if cz == TH_RPAREN { d0 = d0 - 1 } 307 if cz == TH_PIPE { if d0 <= 0 { alts = alts + 1 } } 308 z = z + 1 309 } 310 if hasarg == 0 { if alts < 2 { return nv } } 311 312 var ls: i64 = 0 313 var scan: i64 = 1 314 // F5 state: has a depth-0 arrow been passed? Everything after one is OUTPUT DESCRIPTION until a 315 // segment proves it is a call again by carrying an argument marker. `-> ... verdict=GREEN|RED` 316 // contains a depth-0 pipe INSIDE the description, so "stop at the arrow" alone is not enough -- 317 // the very next segment (`RED`) came back as a verb. A DESCRIPTION CAN CONTAIN THE SEPARATOR THAT 318 // ENDS AN ALTERNATIVE, so re-entry must be EARNED, not assumed. 319 var seen_arrow: i64 = 0 320 while scan == 1 { 321 if ls > gl { scan = 0 } else { 322 // ---- F1: the alternative ends at the next DEPTH-ZERO pipe, never inside <> [] () 323 var le: i64 = ls 324 var dep: i64 = 0 325 var ended_arrow: i64 = 0 326 var sc: i64 = 1 327 while sc == 1 { 328 if le >= gl { sc = 0 } else { 329 let c: i64 = gram[le] as i64 330 if c == TH_LT { dep = dep + 1 } 331 if c == TH_LBRACK { dep = dep + 1 } 332 if c == TH_LPAREN { dep = dep + 1 } 333 if c == TH_GT { dep = dep - 1 } 334 if c == TH_RBRACK { dep = dep - 1 } 335 if c == TH_RPAREN { dep = dep - 1 } 336 var adv: i64 = 1 337 if c == TH_PIPE { if dep <= 0 { sc = 0; adv = 0 } } 338 // ---- F5: an alternative ENDS at its arrow. Everything after `->` describes the 339 // OUTPUT, not the call, and scanning it for verbs reads prose as contract. 340 // CAUGHT BY THE RATCHET ON THIS ORGAN'S OWN TWO ORGANS, not by review: 341 // `... -> per-tooth PASS/FAIL then verdict=GREEN|RED` invented a verb "RED", 342 // `POSITIONAL-ONLY a contract exists ... (<url> <out>)` invented "POSITIONAL-ONLY". 343 // The second one is the sharper lesson: a 3-space-indented header line containing 344 // '<' IS a usage line by the harvester's convention, so PROSE ABOUT VERBS BECOMES 345 // A DECLARED VERB. A detector whose own documentation feeds its input must cut the 346 // description half off, or it will always accuse its own author first. 347 if c == TH_DASH { 348 if dep <= 0 { 349 if le + 1 < gl { if gram[le+1] == (TH_GT as u8) { sc = 0; adv = 0; ended_arrow = 1 } } 350 } 351 } 352 if adv == 1 { le = le + 1 } 353 } 354 } 355 // F5 re-entry test: once an arrow has been passed, a segment is a CALL only if it carries 356 // an argument marker. `RED` does not; `verbscan <grammar-file> <source.nx>` does. 357 var admit: i64 = 1 358 if seen_arrow == 1 { 359 admit = 0 360 var w: i64 = ls 361 while w < le { 362 let cw: i64 = gram[w] as i64 363 if cw == TH_LT { admit = 1 } 364 if cw == TH_LBRACK { admit = 1 } 365 w = w + 1 366 } 367 } 368 if ended_arrow == 1 { seen_arrow = 1 } 369 if admit == 0 { le = le } else { 370 var p: i64 = ls 371 var slot: i64 = 0 372 var take: i64 = 1 373 while take == 1 { 374 var sk: i64 = 1 375 while sk == 1 { 376 if p >= le { sk = 0 } else { 377 if gram[p] == (TH_SPACE as u8) { p = p + 1 } else { sk = 0 } 378 } 379 } 380 if p >= le { take = 0 } else { 381 var q: i64 = p 382 var wk: i64 = 1 383 while wk == 1 { 384 if q >= le { wk = 0 } else { 385 if th_is_wordbyte(gram[q] as i64) == 1 { q = q + 1 } else { wk = 0 } 386 } 387 } 388 let tl: i64 = q - p 389 var okv: i64 = 0 390 if tl > 0 { 391 if tl < TH_VERBCAP { 392 if th_is_alpha(gram[p] as i64) == 1 { 393 if q >= le { okv = 1 } else { 394 if gram[q] == (TH_SPACE as u8) { okv = 1 } 395 } 396 } 397 } 398 } 399 // ---- F3: a token followed by '=' is a description key, not a verb 400 if okv == 1 { 401 var e: i64 = q 402 var es2: i64 = 1 403 while es2 == 1 { 404 if e >= le { es2 = 0 } else { 405 if gram[e] == (TH_SPACE as u8) { e = e + 1 } else { es2 = 0 } 406 } 407 } 408 if e < le { if gram[e] == (TH_EQ as u8) { okv = 0 } } 409 } 410 if okv == 0 { take = 0 } else { 411 let tok: *u8 = ((gram as i64) + p) as *u8 412 var isself: i64 = th_streq(tok, tl, selfname, snl) 413 if isself == 0 { if th_is_toolname(names, nn, tok, tl) == 1 { isself = 1 } } 414 if isself == 1 { 415 if slot == 0 { slot = 1; p = q } else { take = 0 } 416 } else { 417 var dup: i64 = 0 418 var d: i64 = 0 419 while d < nv { 420 let ex: *u8 = ((verbs as i64) + d * TH_VERBCAP) as *u8 421 if th_streq(ex, vlen[d], tok, tl) == 1 { dup = 1; d = nv } else { d = d + 1 } 422 } 423 if dup == 0 { 424 if nv < TH_MAXVERBS { 425 let dst: *u8 = ((verbs as i64) + nv * TH_VERBCAP) as *u8 426 var c2: i64 = 0 427 while c2 < tl { dst[c2] = tok[c2]; c2 = c2 + 1 } 428 dst[tl] = 0 as u8 429 vlen[nv] = tl 430 nv = nv + 1 431 } else { TH_TRUNCATED = TH_TRUNCATED + 1 } 432 } 433 take = 0 434 } 435 } 436 } 437 } 438 } 439 ls = le + 1 440 if le >= gl { scan = 0 } 441 } 442 } 443 return nv 444} 445 446func th_has_literal(src: *u8, sn: i64, verb: *u8, vl: i64) -> i64 { 447 var i: i64 = 0 448 let lim: i64 = sn - vl - 1 449 while i < lim { 450 if src[i] == (TH_QUOTE as u8) { 451 if src[i+vl+1] == (TH_QUOTE as u8) { 452 var j: i64 = 0 453 var m: i64 = 1 454 while j < vl { if src[i+1+j] != verb[j] { m = 0; j = vl } else { j = j + 1 } } 455 if m == 1 { return 1 } 456 } 457 } 458 i = i + 1 459 } 460 return 0 461} 462 463// resolve <root><stem>.nx ; returns 1 and fills out when it exists 464func th_srcpath(root: *u8, stem: *u8, out: *u8) -> i64 { 465 var o: i64 = es_cat(out, 0, root) 466 o = es_cat(out, o, stem) 467 o = es_cat(out, o, ".nx" as *u8) 468 out[o] = 0 as u8 469 return th_exists(out) 470} 471 472func th_verbscan(gramfile: *u8, srcfile: *u8, selfname: *u8) -> i64 { 473 let gl: *i64 = sys_mmap(16) as *i64 474 let gb: *u8 = sys_read_file(gramfile, gl) 475 if (gb as i64) == 0 { thw("VERBSCAN REFUSED unreadable-grammar-file\n" as *u8); return TH_EXIT_REFUSED } 476 var gn: i64 = gl[0] 477 var tr: i64 = 1 478 while tr == 1 { 479 if gn <= 0 { tr = 0 } else { 480 if gb[gn-1] == (TH_NL as u8) { gn = gn - 1 } else { tr = 0 } 481 } 482 } 483 let sl: *i64 = sys_mmap(16) as *i64 484 let sb: *u8 = sys_read_file(srcfile, sl) 485 if (sb as i64) == 0 { thw("VERBSCAN REFUSED unreadable-source\n" as *u8); return TH_EXIT_REFUSED } 486 let verbs: *u8 = sys_mmap(TH_MAXVERBS * TH_VERBCAP) 487 let vlen: *i64 = sys_mmap(8 * TH_MAXVERBS) as *i64 488 let nv: i64 = th_verbs(gb, gn, selfname, es_len(selfname), 0 as *u8, 0, verbs, vlen, 0) 489 var impl: i64 = 0 490 var i: i64 = 0 491 while i < nv { 492 let v: *u8 = ((verbs as i64) + i * TH_VERBCAP) as *u8 493 if th_has_literal(sb, sl[0], v, vlen[i]) == 1 { impl = impl + 1 } 494 i = i + 1 495 } 496 thw("VERBSCAN declared=" as *u8); thn(nv) 497 thw(" implemented=" as *u8); thn(impl) 498 if nv >= TH_UNDECIDABLE_MIN { if impl == 0 { 499 thw(" state=UNDECIDABLE (no declared verb appears as a literal -- this organ cannot see the dispatch)\n" as *u8) 500 return TH_EXIT_OK 501 } } 502 if nv - impl > 0 { 503 thw(" state=DEAD-VERBS\n" as *u8) 504 i = 0 505 while i < nv { 506 let v2: *u8 = ((verbs as i64) + i * TH_VERBCAP) as *u8 507 if th_has_literal(sb, sl[0], v2, vlen[i]) == 0 { thw(" DEAD verb=" as *u8); thw(v2); thw("\n" as *u8) } 508 i = i + 1 509 } 510 return TH_EXIT_OK 511 } 512 thw(" state=CLEAN\n" as *u8) 513 return TH_EXIT_OK 514} 515 516// ---- ratchet ------------------------------------------------------------------ 517// The baseline is a VERBATIM copy of a census log, and both sides derive the SAME KEY from a row, so 518// the comparison can never drift with the detail columns. The key is a SET OF NAMES, never a count: 519// <class>\t<subject> for every class except DEAD-VERB 520// <class>\t<subject>\t<verb=x> for DEAD-VERB, so two dead verbs on one subject are two offenders 521// (keying on the subject alone reported the same subject twice and 522// could not tell "one more verb died" from "the same one, still dead") 523// Returns key length, 0 = not a finding row (comment / short / malformed). 524func th_key(buf: *u8, ls: i64, le: i64, out: *u8, cap: i64) -> i64 { 525 if le <= ls { return 0 } 526 if buf[ls] == (TH_HASH as u8) { return 0 } 527 let f0: *u8 = sys_mmap(TH_NAMECAP) 528 let f1: *u8 = sys_mmap(TH_NAMECAP) 529 let f2: *u8 = sys_mmap(TH_NAMECAP) 530 let l0: i64 = th_field(buf, ls, le, 0, f0, TH_NAMECAP) 531 let l1: i64 = th_field(buf, ls, le, 1, f1, TH_NAMECAP) 532 if l0 == 0 { return 0 } 533 if l1 == 0 { return 0 } 534 var o: i64 = es_cat(out, 0, f0) 535 out[o] = TH_TAB as u8 536 o = o + 1 537 o = es_cat(out, o, f1) 538 if th_streq(f0, l0, "DEAD-VERB" as *u8, 9) == 1 { 539 let l2: i64 = th_field(buf, ls, le, 2, f2, TH_NAMECAP) 540 if l2 > 0 { 541 out[o] = TH_TAB as u8 542 o = o + 1 543 o = es_cat(out, o, f2) 544 } 545 } 546 out[o] = 0 as u8 547 return o 548} 549 550func th_base_has(bb: *u8, bn: i64, want: *u8, wl: i64) -> i64 { 551 let k: *u8 = sys_mmap(TH_PATHCAP) 552 var i: i64 = 0 553 while i < bn { 554 var le: i64 = i 555 var sc: i64 = 1 556 while sc == 1 { if le >= bn { sc = 0 } else { if bb[le] == (TH_NL as u8) { sc = 0 } else { le = le + 1 } } } 557 let kl: i64 = th_key(bb, i, le, k, TH_PATHCAP) 558 if kl > 0 { if th_streq(k, kl, want, wl) == 1 { return 1 } } 559 i = le + 1 560 } 561 return 0 562} 563 564func th_clsname(c: i64) -> *u8 { 565 if c == TH_CLS_PHANTOM { return "PHANTOM" as *u8 } 566 if c == TH_CLS_MISSING_BUILDABLE { return "MISSING-BUILDABLE" as *u8 } 567 if c == TH_CLS_BINARY_NO_SOURCE { return "BINARY-NO-SOURCE" as *u8 } 568 return "OK" as *u8 569} 570 571func main(argc: i64, argv: *i64) -> i64 { 572 if argc < 2 { 573 thw("usage: nx_toolhealth census [allowlist] [schemas] [grammar] [log] | verbscan <grammar-file> <source.nx> [selfname] | ratchet [baseline] [log] | accept [baseline] [log]\n" as *u8) 574 sys_exit(TH_EXIT_USAGE); return TH_EXIT_USAGE 575 } 576 let verb: *u8 = argv[1] as *u8 577 let vl: i64 = es_len(verb) 578 579 if th_streq(verb, vl, "verbscan" as *u8, 8) == 1 { 580 if argc < 4 { thw("usage: nx_toolhealth verbscan <grammar-file> <source.nx> [selfname]\n" as *u8); sys_exit(TH_EXIT_USAGE); return TH_EXIT_USAGE } 581 var sn: *u8 = "" as *u8 582 if argc >= 5 { sn = argv[4] as *u8 } 583 let rc: i64 = th_verbscan(argv[2] as *u8, argv[3] as *u8, sn) 584 sys_exit(rc); return rc 585 } 586 587 var do_census: i64 = 0 588 var do_ratchet: i64 = 0 589 var do_accept: i64 = 0 590 if th_streq(verb, vl, "census" as *u8, 6) == 1 { do_census = 1 } 591 if th_streq(verb, vl, "ratchet" as *u8, 7) == 1 { do_ratchet = 1 } 592 if th_streq(verb, vl, "accept" as *u8, 6) == 1 { do_accept = 1 } 593 if do_census == 0 { if do_ratchet == 0 { if do_accept == 0 { 594 thw("usage: nx_toolhealth census | verbscan | ratchet | accept\n" as *u8) 595 sys_exit(TH_EXIT_USAGE); return TH_EXIT_USAGE 596 } } } 597 598 var p_allow: *u8 = TH_DEF_ALLOW 599 var p_schemas: *u8 = TH_DEF_SCHEMAS 600 var p_grammar: *u8 = TH_DEF_GRAMMAR 601 var p_log: *u8 = TH_DEF_LOG 602 var p_base: *u8 = TH_DEF_BASE 603 // the source roots are ARGUMENTS, not only consts: the census must be runnable from any cwd (the 604 // build runner works from buildroot, the beat from the nishihost root) AND a gate must be able to 605 // point it at a /tmp fixture tree. A hardcoded relative root would silently read every subject as 606 // BINARY-NO-SOURCE from the wrong directory -- a confident wrong answer, not an error. 607 var p_srca: *u8 = TH_SRC_A 608 var p_srcb: *u8 = TH_SRC_B 609 if do_census == 1 { 610 if argc >= 3 { p_allow = argv[2] as *u8 } 611 if argc >= 4 { p_schemas = argv[3] as *u8 } 612 if argc >= 5 { p_grammar = argv[4] as *u8 } 613 if argc >= 6 { p_log = argv[5] as *u8 } 614 if argc >= 7 { p_base = argv[6] as *u8 } 615 if argc >= 8 { p_srca = argv[7] as *u8 } 616 if argc >= 9 { p_srcb = argv[8] as *u8 } 617 } else { 618 if argc >= 3 { p_base = argv[2] as *u8 } 619 if argc >= 4 { p_log = argv[3] as *u8 } 620 } 621 622 // ---- ratchet / accept re-read the durable log rather than re-scanning the population ---- 623 if do_census == 0 { 624 let ll: *i64 = sys_mmap(16) as *i64 625 let lb: *u8 = sys_read_file(p_log, ll) 626 if (lb as i64) == 0 { thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"no census log -- run `census` first\"}\n" as *u8); sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED } 627 let bl2: *i64 = sys_mmap(16) as *i64 628 let bb: *u8 = sys_read_file(p_base, bl2) 629 var bn: i64 = 0 630 if (bb as i64) != 0 { bn = bl2[0] } 631 if do_accept == 1 { 632 let fd: i64 = sys_openat_wr(p_base, TH_MODE_FILE) 633 if fd < 0 { thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"cannot write baseline\"}\n" as *u8); sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED } 634 // adopt the log VERBATIM -- both sides then derive the key by the same function, so the 635 // baseline can never drift from the census that produced it 636 sys_write(fd, lb, ll[0]) 637 sys_close(fd) 638 var adopted: i64 = 0 639 var i: i64 = 0 640 let k0: *u8 = sys_mmap(TH_PATHCAP) 641 while i < ll[0] { 642 var le: i64 = i 643 var sc: i64 = 1 644 while sc == 1 { if le >= ll[0] { sc = 0 } else { if lb[le] == (TH_NL as u8) { sc = 0 } else { le = le + 1 } } } 645 if th_key(lb, i, le, k0, TH_PATHCAP) > 0 { adopted = adopted + 1 } 646 i = le + 1 647 } 648 thw("{\"organ\":\"nx_toolhealth\",\"verb\":\"accept\",\"adopted_rows\":" as *u8); thn(adopted) 649 thw(",\"baseline\":\"" as *u8); thw(p_base); thw("\"}\n" as *u8) 650 sys_exit(TH_EXIT_OK); return TH_EXIT_OK 651 } 652 // ratchet: NEW = in log, not in baseline 653 var newn: i64 = 0 654 var total: i64 = 0 655 var i2: i64 = 0 656 let k2: *u8 = sys_mmap(TH_PATHCAP) 657 while i2 < ll[0] { 658 var le2: i64 = i2 659 var s2: i64 = 1 660 while s2 == 1 { if le2 >= ll[0] { s2 = 0 } else { if lb[le2] == (TH_NL as u8) { s2 = 0 } else { le2 = le2 + 1 } } } 661 let kl2: i64 = th_key(lb, i2, le2, k2, TH_PATHCAP) 662 if kl2 > 0 { 663 total = total + 1 664 if bn > 0 { 665 if th_base_has(bb, bn, k2, kl2) == 0 { 666 thw("NEW offender=" as *u8); thw(k2); thw("\n" as *u8) 667 newn = newn + 1 668 } 669 } 670 } 671 i2 = le2 + 1 672 } 673 if bn == 0 { 674 let fd2: i64 = sys_openat_wr(p_base, TH_MODE_FILE) 675 if fd2 >= 0 { sys_write(fd2, lb, ll[0]); sys_close(fd2) } 676 thw("{\"organ\":\"nx_toolhealth\",\"verb\":\"ratchet\",\"baseline\":\"SELF-BASELINED-ON-FIRST-SIGHT\",\"rows\":" as *u8); thn(total) 677 thw(",\"verdict\":\"GREEN\"}\n" as *u8) 678 sys_exit(TH_EXIT_OK); return TH_EXIT_OK 679 } 680 thw("{\"organ\":\"nx_toolhealth\",\"verb\":\"ratchet\",\"rows\":" as *u8); thn(total) 681 thw(",\"new_offenders\":" as *u8); thn(newn) 682 if newn > 0 { 683 thw(",\"verdict\":\"RED\",\"note\":\"each NEW row is named above; fix it or adopt with `accept`\"}\n" as *u8) 684 sys_exit(TH_EXIT_REGRESSED); return TH_EXIT_REGRESSED 685 } 686 thw(",\"verdict\":\"GREEN\"}\n" as *u8) 687 sys_exit(TH_EXIT_OK); return TH_EXIT_OK 688 } 689 690 // ---- CENSUS ---------------------------------------------------------------- 691 let al: *i64 = sys_mmap(16) as *i64 692 let ab: *u8 = sys_read_file(p_allow, al) 693 if (ab as i64) == 0 { thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"tool_allowlist.conf unreadable\"}\n" as *u8); sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED } 694 let an: i64 = al[0] 695 if an <= 0 { thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"allowlist empty -- a zero census is not a clean census\"}\n" as *u8); sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED } 696 697 let scl: *i64 = sys_mmap(16) as *i64 698 let scb: *u8 = sys_read_file(p_schemas, scl) 699 var scn: i64 = 0 700 if (scb as i64) != 0 { scn = scl[0] } 701 let grl: *i64 = sys_mmap(16) as *i64 702 let grb: *u8 = sys_read_file(p_grammar, grl) 703 var grn: i64 = 0 704 if (grb as i64) != 0 { grn = grl[0] } 705 706 let rw_name_off: *i64 = sys_mmap(8 * TH_ROWCAP) as *i64 707 let rw_name_len: *i64 = sys_mmap(8 * TH_ROWCAP) as *i64 708 let rw_pinned: *i64 = sys_mmap(8 * TH_ROWCAP) as *i64 709 let rw_subj: *i64 = sys_mmap(8 * TH_ROWCAP) as *i64 710 let sj_stem: *u8 = sys_mmap(TH_SUBJCAP * TH_NAMECAP) 711 let sj_stem_len: *i64 = sys_mmap(8 * TH_SUBJCAP) as *i64 712 let sj_ls: *i64 = sys_mmap(8 * TH_SUBJCAP) as *i64 713 let sj_le: *i64 = sys_mmap(8 * TH_SUBJCAP) as *i64 714 let sj_refs: *i64 = sys_mmap(8 * TH_SUBJCAP) as *i64 715 let sj_nongreen: *i64 = sys_mmap(8 * TH_SUBJCAP) as *i64 716 717 var rows: i64 = 0 718 var subs: i64 = 0 719 var refs_nongreen: i64 = 0 720 let nm: *u8 = sys_mmap(TH_NAMECAP) 721 let elf: *u8 = sys_mmap(TH_PATHCAP) 722 let st: *u8 = sys_mmap(TH_NAMECAP) 723 let stem: *u8 = sys_mmap(TH_NAMECAP) 724 725 var i: i64 = 0 726 while i < an { 727 var le: i64 = i 728 var sc: i64 = 1 729 while sc == 1 { if le >= an { sc = 0 } else { if ab[le] == (TH_NL as u8) { sc = 0 } else { le = le + 1 } } } 730 var ok: i64 = 1 731 if le <= i { ok = 0 } 732 if ok == 1 { if ab[i] == (TH_HASH as u8) { ok = 0 } } 733 if ok == 1 { 734 let nl: i64 = th_field(ab, i, le, 0, nm, TH_NAMECAP) 735 let el: i64 = th_field(ab, i, le, 1, elf, TH_PATHCAP) 736 let stl: i64 = th_field(ab, i, le, 2, st, TH_NAMECAP) 737 if nl == 0 { ok = 0 } 738 if el == 0 { ok = 0 } 739 if ok == 1 { 740 if rows >= TH_ROWCAP { 741 thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"allowlist rows exceeded TH_ROWCAP -- refusing a partial census\"}\n" as *u8) 742 sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED 743 } 744 rw_name_off[rows] = i 745 rw_name_len[rows] = nl 746 var pin: i64 = 0 747 if th_count_fields(ab, i, le) >= 4 { pin = 1 } 748 rw_pinned[rows] = pin 749 var green: i64 = 0 750 if stl == 5 { if th_streq(st, 5, "GREEN" as *u8, 5) == 1 { green = 1 } } 751 let sl2: i64 = th_stem(elf, el, stem, TH_NAMECAP) 752 var found: i64 = 0 - 1 753 var s: i64 = 0 754 while s < subs { 755 let ex: *u8 = ((sj_stem as i64) + s * TH_NAMECAP) as *u8 756 if th_streq(ex, sj_stem_len[s], stem, sl2) == 1 { found = s; s = subs } else { s = s + 1 } 757 } 758 if found < 0 { 759 if subs >= TH_SUBJCAP { 760 thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"subjects exceeded TH_SUBJCAP -- refusing a partial census\"}\n" as *u8) 761 sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED 762 } 763 let dst: *u8 = ((sj_stem as i64) + subs * TH_NAMECAP) as *u8 764 var c: i64 = 0 765 while c < sl2 { dst[c] = stem[c]; c = c + 1 } 766 dst[sl2] = 0 as u8 767 sj_stem_len[subs] = sl2 768 sj_ls[subs] = i 769 sj_le[subs] = le 770 sj_refs[subs] = 0 771 sj_nongreen[subs] = 0 772 found = subs 773 subs = subs + 1 774 } 775 rw_subj[rows] = found 776 sj_refs[found] = sj_refs[found] + 1 777 if green == 0 { sj_nongreen[found] = sj_nongreen[found] + 1; refs_nongreen = refs_nongreen + 1 } 778 rows = rows + 1 779 } 780 } 781 i = le + 1 782 } 783 784 sys_mkdir(TH_STATUS_DIR, TH_MODE_DIR) 785 sys_unlinkat(p_log) 786 let lf: i64 = sys_openat_append(p_log, TH_MODE_FILE) 787 if lf < 0 { thw("{\"organ\":\"nx_toolhealth\",\"refused\":\"cannot open census log for append\"}\n" as *u8); sys_exit(TH_EXIT_REFUSED); return TH_EXIT_REFUSED } 788 let hdr: *u8 = "# NX-DERIVED: regenerated artefact, not authored memory. nx_toolhealth census worklist.\n# TAB-separated: <class>\\t<subject>\\t<detail...> -- one row per finding, appended AS IT IS FOUND.\n" as *u8 789 sys_write(lf, hdr, es_len(hdr)) 790 791 var c_ok: i64 = 0 792 var c_mb: i64 = 0 793 var c_ph: i64 = 0 794 var c_bns: i64 = 0 795 var a_unreach: i64 = 0 796 var hc_clean: i64 = 0 797 var hc_dead_subjects: i64 = 0 798 var hc_dead_verbs: i64 = 0 799 var hc_pinned: i64 = 0 800 var hc_nogram: i64 = 0 801 var hc_positional: i64 = 0 802 var hc_undec: i64 = 0 803 var hc_nosrc: i64 = 0 804 var verbs_declared_total: i64 = 0 805 var verbs_impl_total: i64 = 0 806 807 let srcp: *u8 = sys_mmap(TH_PATHCAP) 808 let gram: *u8 = sys_mmap(TH_GRAMCAP) 809 let verbs: *u8 = sys_mmap(TH_MAXVERBS * TH_VERBCAP) 810 let vlen: *i64 = sys_mmap(8 * TH_MAXVERBS) as *i64 811 let line: *u8 = sys_mmap(TH_LINEBUF) 812 let srclen: *i64 = sys_mmap(16) as *i64 813 814 var s2: i64 = 0 815 while s2 < subs { 816 let stemp: *u8 = ((sj_stem as i64) + s2 * TH_NAMECAP) as *u8 817 // the elf field is not NUL-terminated inside the allowlist buffer -- copy it out first 818 th_field(ab, sj_ls[s2], sj_le[s2], 1, elf, TH_PATHCAP) 819 let has_elf: i64 = th_exists(elf) 820 var has_src: i64 = th_srcpath(p_srca, stemp, srcp) 821 if has_src == 0 { has_src = th_srcpath(p_srcb, stemp, srcp) } 822 var cls: i64 = TH_CLS_OK 823 if has_elf == 0 { 824 if has_src == 0 { cls = TH_CLS_PHANTOM } else { cls = TH_CLS_MISSING_BUILDABLE } 825 } else { 826 if has_src == 0 { cls = TH_CLS_BINARY_NO_SOURCE } 827 } 828 if cls == TH_CLS_OK { c_ok = c_ok + 1 } 829 if cls == TH_CLS_MISSING_BUILDABLE { c_mb = c_mb + 1 } 830 if cls == TH_CLS_PHANTOM { c_ph = c_ph + 1 } 831 if cls == TH_CLS_BINARY_NO_SOURCE { c_bns = c_bns + 1 } 832 if sj_nongreen[s2] > 0 { a_unreach = a_unreach + 1 } 833 834 // half-capable: union the verbs declared by every NON-PINNED name of this subject 835 var nv: i64 = 0 836 var anyname: i64 = 0 837 var allpinned: i64 = 1 838 var r: i64 = 0 839 while r < rows { 840 if rw_subj[r] == s2 { 841 if rw_pinned[r] == 0 { 842 allpinned = 0 843 let key: *u8 = ((ab as i64) + rw_name_off[r]) as *u8 844 var gn2: i64 = 0 845 if scn > 0 { gn2 = th_lookup(scb, scn, key, rw_name_len[r], 7, gram, TH_GRAMCAP) } 846 if gn2 == 0 { if grn > 0 { gn2 = th_lookup(grb, grn, key, rw_name_len[r], 1, gram, TH_GRAMCAP) } } 847 if gn2 > 0 { 848 anyname = 1 849 // copy the tool name out for the self-name test 850 var kc: i64 = 0 851 while kc < rw_name_len[r] { nm[kc] = key[kc]; kc = kc + 1 } 852 nm[rw_name_len[r]] = 0 as u8 853 nv = th_verbs(gram, gn2, nm, rw_name_len[r], ab, an, verbs, vlen, nv) 854 } 855 } 856 } 857 r = r + 1 858 } 859 860 var hc: i64 = TH_HC_CLEAN 861 var dead: i64 = 0 862 if allpinned == 1 { hc = TH_HC_PINNED; hc_pinned = hc_pinned + 1 } else { 863 if has_src == 0 { hc = TH_HC_NOSOURCE; hc_nosrc = hc_nosrc + 1 } else { 864 // TWO BUCKETS, NOT ONE. v1 folded "no grammar row exists at all" together with "a 865 // grammar row exists and declares no verb", and the merged headline read 618 of 959 -- 866 // a number that would have sent the next reader on a sweep over hundreds of tools that 867 // are perfectly fine. A POSITIONAL contract (`<url> <out>`) declares no verb BY DESIGN 868 // and is not a defect; NO-GRAMMAR means an agent has no contract to read at all. 869 // Opposite remedies, so they can never share a counter. 870 if anyname == 0 { hc = TH_HC_NOGRAMMAR; hc_nogram = hc_nogram + 1 } else { 871 if nv == 0 { hc = TH_HC_POSITIONAL; hc_positional = hc_positional + 1 } else { 872 let sb2: *u8 = sys_read_file(srcp, srclen) 873 if (sb2 as i64) == 0 { hc = TH_HC_NOSOURCE; hc_nosrc = hc_nosrc + 1 } else { 874 var impl: i64 = 0 875 var vi: i64 = 0 876 while vi < nv { 877 let v: *u8 = ((verbs as i64) + vi * TH_VERBCAP) as *u8 878 if th_has_literal(sb2, srclen[0], v, vlen[vi]) == 1 { impl = impl + 1 } 879 vi = vi + 1 880 } 881 verbs_declared_total = verbs_declared_total + nv 882 verbs_impl_total = verbs_impl_total + impl 883 dead = nv - impl 884 if nv >= TH_UNDECIDABLE_MIN { if impl == 0 { hc = TH_HC_UNDECIDABLE; hc_undec = hc_undec + 1; dead = 0 } } 885 if hc == TH_HC_CLEAN { 886 if dead > 0 { 887 hc = TH_HC_DEAD 888 hc_dead_subjects = hc_dead_subjects + 1 889 hc_dead_verbs = hc_dead_verbs + dead 890 } else { hc_clean = hc_clean + 1 } 891 } 892 if hc == TH_HC_DEAD { 893 vi = 0 894 while vi < nv { 895 let v2: *u8 = ((verbs as i64) + vi * TH_VERBCAP) as *u8 896 if th_has_literal(sb2, srclen[0], v2, vlen[vi]) == 0 { 897 var lo: i64 = es_cat(line, 0, "DEAD-VERB\t" as *u8) 898 lo = es_cat(line, lo, stemp) 899 lo = es_cat(line, lo, "\tverb=" as *u8) 900 lo = es_cat(line, lo, v2) 901 lo = es_cat(line, lo, "\tsrc=" as *u8) 902 lo = es_cat(line, lo, srcp) 903 lo = es_cat(line, lo, "\tremedy=implement-or-remove-from-grammar\n" as *u8) 904 sys_write(lf, line, lo) 905 } 906 vi = vi + 1 907 } 908 } 909 sys_free_file(sb2, srclen[0]) 910 } 911 } 912 } 913 } 914 } 915 916 if cls != TH_CLS_OK { 917 var lo2: i64 = es_cat(line, 0, th_clsname(cls)) 918 line[lo2] = TH_TAB as u8 919 lo2 = lo2 + 1 920 lo2 = es_cat(line, lo2, stemp) 921 lo2 = es_cat(line, lo2, "\telf=" as *u8) 922 lo2 = es_cat(line, lo2, elf) 923 lo2 = es_cat(line, lo2, "\trefs=" as *u8) 924 lo2 = es_catn(line, lo2, sj_refs[s2]) 925 lo2 = es_cat(line, lo2, "\tremedy=" as *u8) 926 if cls == TH_CLS_PHANTOM { lo2 = es_cat(line, lo2, "fix-or-delete-the-caller-it-can-never-be-built" as *u8) } 927 if cls == TH_CLS_MISSING_BUILDABLE { lo2 = es_cat(line, lo2, "build" as *u8) } 928 if cls == TH_CLS_BINARY_NO_SOURCE { lo2 = es_cat(line, lo2, "adjudicate-ships-inside-another-artifact-or-source-lost" as *u8) } 929 line[lo2] = TH_NL as u8 930 lo2 = lo2 + 1 931 sys_write(lf, line, lo2) 932 } 933 if sj_nongreen[s2] > 0 { 934 var lo3: i64 = es_cat(line, 0, "UNREACHABLE\t" as *u8) 935 lo3 = es_cat(line, lo3, stemp) 936 lo3 = es_cat(line, lo3, "\tnon_green_refs=" as *u8) 937 lo3 = es_catn(line, lo3, sj_nongreen[s2]) 938 lo3 = es_cat(line, lo3, "\tremedy=lane-A-owns-the-allowlist-repair\n" as *u8) 939 sys_write(lf, line, lo3) 940 } 941 if hc == TH_HC_NOGRAMMAR { 942 var lo5: i64 = es_cat(line, 0, "NO-GRAMMAR\t" as *u8) 943 lo5 = es_cat(line, lo5, stemp) 944 lo5 = es_cat(line, lo5, "\trefs=" as *u8) 945 lo5 = es_catn(line, lo5, sj_refs[s2]) 946 lo5 = es_cat(line, lo5, "\tremedy=add-a-2-3-space-usage-line-to-the-header-then-nx_toolgrammar\n" as *u8) 947 sys_write(lf, line, lo5) 948 } 949 if hc == TH_HC_UNDECIDABLE { 950 var lo4: i64 = es_cat(line, 0, "DISPATCH-UNDECIDABLE\t" as *u8) 951 lo4 = es_cat(line, lo4, stemp) 952 lo4 = es_cat(line, lo4, "\tdeclared=" as *u8) 953 lo4 = es_catn(line, lo4, nv) 954 lo4 = es_cat(line, lo4, "\tremedy=read-the-source-this-detector-cannot-see-its-dispatch\n" as *u8) 955 sys_write(lf, line, lo4) 956 } 957 s2 = s2 + 1 958 } 959 sys_close(lf) 960 961 thw("{\"organ\":\"nx_toolhealth\",\"population\":\"" as *u8); thw(p_allow) 962 thw("\",\"registered_rows\":" as *u8); thn(rows) 963 thw(",\"subjects\":" as *u8); thn(subs) 964 thw(",\"broken_partition\":{\"OK\":" as *u8); thn(c_ok) 965 thw(",\"MISSING-BUILDABLE\":" as *u8); thn(c_mb) 966 thw(",\"PHANTOM\":" as *u8); thn(c_ph) 967 thw(",\"BINARY-NO-SOURCE\":" as *u8); thn(c_bns) 968 thw(",\"sum\":" as *u8); thn(c_ok + c_mb + c_ph + c_bns) 969 thw("},\"partition_reconciles\":" as *u8) 970 if c_ok + c_mb + c_ph + c_bns == subs { thw("1" as *u8) } else { thw("0" as *u8) } 971 thw(",\"axis_unreachable_subjects\":" as *u8); thn(a_unreach) 972 thw(",\"axis_unreachable_refs\":" as *u8); thn(refs_nongreen) 973 thw(",\"halfcapable\":{\"CLEAN\":" as *u8); thn(hc_clean) 974 thw(",\"DEAD-VERB-SUBJECTS\":" as *u8); thn(hc_dead_subjects) 975 thw(",\"DEAD-VERBS\":" as *u8); thn(hc_dead_verbs) 976 thw(",\"PINNED\":" as *u8); thn(hc_pinned) 977 thw(",\"NO-GRAMMAR\":" as *u8); thn(hc_nogram) 978 thw(",\"POSITIONAL-ONLY\":" as *u8); thn(hc_positional) 979 thw(",\"DISPATCH-UNDECIDABLE\":" as *u8); thn(hc_undec) 980 thw(",\"NO-SOURCE\":" as *u8); thn(hc_nosrc) 981 thw(",\"sum\":" as *u8); thn(hc_clean + hc_dead_subjects + hc_pinned + hc_nogram + hc_positional + hc_undec + hc_nosrc) 982 thw("},\"halfcapable_partition_reconciles\":" as *u8) 983 if hc_clean + hc_dead_subjects + hc_pinned + hc_nogram + hc_positional + hc_undec + hc_nosrc == subs { thw("1" as *u8) } else { thw("0" as *u8) } 984 thw(",\"verbs_declared\":" as *u8); thn(verbs_declared_total) 985 thw(",\"verbs_implemented\":" as *u8); thn(verbs_impl_total) 986 thw(",\"verb_table_overflows\":" as *u8); thn(TH_TRUNCATED) 987 thw(",\"worklist\":\"" as *u8); thw(p_log) 988 // phrased as a RULE, never as a list of the buckets printed above it -- a note that enumerates its 989 // own siblings goes stale the moment a bucket is added, and it drifts toward understatement 990 thw("\",\"note\":\"UNREACHABLE is a separate AXIS, never a partition member. In the halfcapable partition ONLY CLEAN is a clean bill and ONLY DEAD-VERB-SUBJECTS is an accusation; every other bucket is an ABSTENTION with its own remedy.\"}\n" as *u8) 991 sys_exit(TH_EXIT_OK) 992 return TH_EXIT_OK 993}