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}