code wiki / _hdl_build / nx_toolgrammar.nx

nx_toolgrammar.nx source

↩ module page · 602 lines · 35677 B

1// nx_toolgrammar.nx -- CALL-GRAMMAR HARVESTER (2026-08-06). Derives each tool's argv CONTRACT from its 2// own source header and emits knowledge/tool_grammar.conf, which nx_tools_api reads as the col8 FALLBACK 3// so tools/list serves a real call grammar instead of the generic "positional CLI args" placeholder. 4// WHY A SEPARATE FILE, NOT A REWRITE: tool_schemas.conf is a SHARED registry and col8 there is 5// HAND-AUTHORED. An authored col8 must always win over a derived one, and a derived value must never 6// overwrite a human's. Emitting a sibling file keeps this ADDITIVE and reversible (delete the file) and 7// keeps the precedence obvious: authored col8 > derived grammar > generic placeholder. 8// MEASURED 2026-08-06 over the live tools/list: 749 of 869 tools (86.2%) had no col8 at all -- the gap 9// tool_schemas.conf itself named on 2026-07-17 as "the tool-schema SOTA gap" and nothing ever derived. 10// THE CONVENTION, read off real organs (nx_pm_board, nx_ws_miner, nx_atlas_discover, nx_feeder), NOT 11// invented: a usage line is a `//` comment indented by EXACTLY 2-3 spaces whose text carries a grammar 12// marker (`<`, `[`, or `->`). 1 space is prose ("// nx_x.nx -- ...", "// license_tier: ..."); 4+ spaces 13// is a continuation ("// defaults: ...", "// out row: ..."). The first token may be the tool's 14// OWN NAME (nx_pm_board [frontierpfx] ...) or a bare VERB (mine <journal> ...) -- both are real and an 15// earlier name-anchored scan found only 131 of 749 precisely because it assumed the former. 16// HONEST: no source / no usage line / too short => SKIPPED + COUNTED, never guessed (blank beats bad). 17// Runs of whitespace collapse to one space and TAB/controls are scrubbed, so a header can never inject 18// a column or split a row. 19// nx_toolgrammar -> writes knowledge/tool_grammar.conf, prints a JSON census on stdout 20// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 21import "nx_mgmt_api.nx" 22import "nx_syscalls.nx" 23 24// sized: matches nx_schema_backfill's allowlist envelope; refuse-on-full keeps the census honest 25const TG_ALCAP: i64 = 1 << 18 26// sized: header blocks are long prose; 8KiB comfortably covers the documented ones measured 27const TG_HDRCAP: i64 = 8192 28// sized: a joined grammar of up to 4 usage lines; hard cap keeps rows lean 29const TG_GRAMCAP: i64 = 400 30// derived: shortest honest grammar seen is ~8 bytes ("<url> ..."); below = not a contract, skip 31const TG_MINGRAM: i64 = 8 32// sized: tool names are sanitized [a-zA-Z0-9_] <= 120 by the register API 33const TG_NAMECAP: i64 = 128 34// sized: elf paths in the allowlist are absolute NAS paths well under this 35const TG_PATHCAP: i64 = 512 36// declared: at most this many usage lines join into one grammar 37const TG_MAXLINES: i64 = 4 38 39const TG_OUT: *u8 = "knowledge/tool_grammar.conf" as *u8 40 41// Module-level mutable is `static`, never `var` (banked 2026-08-01). Counts usage-line candidates the 42// discriminator threw out, so the census REPORTS its own filtering instead of me inferring it from a diff. 43static TG_REJECTED: i64 = 0 44 45func tgw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 46func tgn(v: i64) -> i64 { 47 let b: *u8 = sys_mmap(32) 48 var x: i64 = v 49 var i: i64 = 31 50 if x == 0 { b[i] = 48 as u8; i = i - 1 } 51 while x > 0 { b[i] = ((48 + (x - ((x / 10) * 10))) as u8); x = x / 10; i = i - 1 } 52 sys_write(1, ((b as i64) + i + 1) as *u8, 31 - i) 53 return 0 54} 55 56func tg_ends(s: *u8, sl: i64, suf: *u8, fl: i64) -> i64 { 57 if sl < fl { return 0 } 58 var i: i64 = 0 59 while i < fl { if s[sl-fl+i] != suf[i] { return 0 } i = i + 1 } 60 return 1 61} 62 63// Read path's header window and join its usage lines into `out`. Returns length, 0 = none, -1 = unreadable. 64func tg_grammar_from_header(path: *u8, out: *u8) -> i64 { 65 let fd: i64 = sys_openat_rd(path) 66 if fd < 0 { return 0 - 1 } 67 let hb: *u8 = sys_mmap(TG_HDRCAP) 68 let hn: i64 = sys_read(fd, hb, TG_HDRCAP - 1) 69 sys_close(fd) 70 if hn <= 2 { return 0 } 71 var o: i64 = 0 72 var found: i64 = 0 73 var ls: i64 = 0 74 var scan: i64 = 1 75 while scan == 1 { 76 if ls >= hn { scan = 0 } else { 77 var le: i64 = ls 78 var sc: i64 = 1 79 while sc == 1 { if le >= hn { sc = 0 } else { if hb[le] == (10 as u8) { sc = 0 } else { le = le + 1 } } } 80 var iscmt: i64 = 0 81 if le - ls >= 4 { if hb[ls] == (47 as u8) { if hb[ls+1] == (47 as u8) { iscmt = 1 } } } 82 if iscmt == 1 { 83 var p: i64 = ls + 2 84 var sp: i64 = 0 85 var go: i64 = 1 86 while go == 1 { 87 if p >= le { go = 0 } else { 88 if hb[p] == (32 as u8) { sp = sp + 1; p = p + 1 } else { go = 0 } 89 } 90 } 91 var cand: i64 = 0 92 if sp >= 2 { if sp <= 3 { if p < le { cand = 1 } } } 93 if cand == 1 { 94 // A usage line carries an ARG token ('<' or '[') or an output arrow ('->'). 95 var hasarg: i64 = 0 96 var hasarrow: i64 = 0 97 var q: i64 = p 98 while q < le { 99 let c: i64 = hb[q] as i64 100 if c == 60 { hasarg = 1 } 101 if c == 91 { hasarg = 1 } 102 if c == 45 { if q + 1 < le { if hb[q+1] == (62 as u8) { hasarrow = 1 } } } 103 q = q + 1 104 } 105 var mark: i64 = 0 106 if hasarg == 1 { mark = 1 } 107 if hasarrow == 1 { mark = 1 } 108 // TWEAK (measured): pass 1 emitted 439 rows of which 60 (13.7%) were ENUMERATED PROSE 109 // that merely contained an arrow -- gate teeth ("T1 LOW temperature concentrates on the 110 // argmax"), numbered lists ("1) RELATIONSHIPS to tend"), bullets, quoted requirements. 111 // Two-part discriminator, because neither half alone is sufficient: 112 // * uppercase-led is NOT disqualifying -- "PROJ <pid> <owner> <title>" and 113 // "MEMBER <gid> <name>" are REAL grammars with uppercase verbs (nishi_project, 114 // vizsla_group), so a lowercase-only rule would delete correct contracts; 115 // * arrow-only is NOT disqualifying either -- "nx_recall_bench -> JSON scorecard" 116 // is a real argless contract. 117 // So: a line carrying an ARG token is a grammar unless it opens like an enumerated 118 // item; an ARROW-ONLY line additionally must open with a lowercase verb or the tool's 119 // own (always-lowercase) name. 120 var reject: i64 = 0 121 let c0: i64 = hb[p] as i64 122 var c1: i64 = 0 123 if p + 1 < le { c1 = hb[p+1] as i64 } 124 if c0 == 42 { reject = 1 } 125 if c0 == 34 { reject = 1 } 126 if c0 == 35 { reject = 1 } 127 if c0 == 45 { if c1 != 45 { reject = 1 } } 128 if c0 >= 48 { if c0 <= 57 { reject = 1 } } 129 if c0 == 40 { if c1 >= 48 { if c1 <= 57 { reject = 1 } } } 130 if c0 >= 65 { if c0 <= 90 { if c1 >= 48 { if c1 <= 57 { reject = 1 } } } } 131 if hasarg == 0 { 132 if c0 < 97 { reject = 1 } 133 if c0 > 122 { reject = 1 } 134 } 135 if reject == 1 { mark = 0; TG_REJECTED = TG_REJECTED + 1 } 136 if mark == 1 { 137 if found > 0 { 138 if o < TG_GRAMCAP - 4 { out[o] = 32 as u8; o = o + 1; out[o] = 124 as u8; o = o + 1; out[o] = 32 as u8; o = o + 1 } 139 } 140 var lastsp: i64 = 0 141 var w: i64 = p 142 while w < le { 143 var c2: i64 = hb[w] as i64 144 if c2 < 32 { c2 = 32 } 145 if c2 == 9 { c2 = 32 } 146 if c2 == 32 { 147 if lastsp == 0 { if o < TG_GRAMCAP - 1 { out[o] = c2 as u8; o = o + 1 } } 148 lastsp = 1 149 } else { 150 lastsp = 0 151 if o < TG_GRAMCAP - 1 { out[o] = c2 as u8; o = o + 1 } 152 } 153 w = w + 1 154 } 155 found = found + 1 156 if found >= TG_MAXLINES { scan = 0 } 157 } 158 } 159 } 160 ls = le + 1 161 } 162 } 163 var tc: i64 = 1 164 while tc == 1 { if o > 0 { if out[o-1] == (32 as u8) { o = o - 1 } else { tc = 0 } } else { tc = 0 } } 165 out[o] = 0 as u8 166 if o < TG_MINGRAM { return 0 } 167 return o 168} 169 170// sized: pass 2 scans the WHOLE source, not just the header window 171const TG_SRCCAP: i64 = 262144 172static TG_FROM_HEADER: i64 = 0 173static TG_FROM_USAGE: i64 = 0 174 175// PASS 2 (2026-08-06): the organ's OWN `usage:` string literal, used ONLY when the header convention 176// yielded nothing. MEASURED: 705 of the tree's sources carry a `usage:` literal while 466 registered tools 177// had no header usage line at all -- the contract was in the binary's own help text, one convention away. 178// Still VERBATIM source text, nothing synthesised. The literal ends at the closing quote or at an escaped 179// \n, whichever comes first, so a multi-line printf cannot bleed into the row. 180// ★ WHEN ONE CONVENTION PLATEAUS, LOOK FOR THE SECOND ONE THE CODEBASE ALREADY USES -- DO NOT LOOSEN THE FIRST. 181// (Loosening the header rule was measured earlier this session and cost precision: prose false-positives 182// ran 13.7% until a discriminator pushed them to 4.5%. A NEW GROUNDED SOURCE BEATS A LOOSER OLD ONE.) 183func tg_usage_literal(path: *u8, out: *u8, stem: *u8, stl: i64) -> i64 { 184 let fd: i64 = sys_openat_rd(path) 185 if fd < 0 { return 0 - 1 } 186 let sb: *u8 = sys_mmap(TG_SRCCAP) 187 let sn: i64 = sys_read(fd, sb, TG_SRCCAP - 1) 188 sys_close(fd) 189 if sn <= 6 { return 0 } 190 let ndl: *u8 = "usage:" as *u8 191 // MEASURED DEFECT in the first cut of this pass: taking the FIRST `usage:` literal gave nx_services, 192 // nx_health and nx_mgmt the grammar `nx_mgmt_call <METHOD> <path> [json_body]` -- the usage of the 193 // shared DRIVER, not of the pinned argless tool. An agent reading that would pass three arguments to 194 // a tool that takes none, which is worse than telling it nothing. 195 // ★ A CONTRACT HARVESTED FROM A SHARED SOURCE MUST NAME THE TOOL IT IS FILED UNDER. 196 // So: accept a literal ONLY if its text mentions this tool's own stem. No mention => SKIP and COUNT 197 // (blank beats bad), exactly as the header pass already refuses an undocumented organ. 198 var i: i64 = 0 199 var found: i64 = 0 - 1 200 while i + 6 <= sn { 201 var j: i64 = 0 202 var hit: i64 = 1 203 while j < 6 { if sb[i+j] != ndl[j] { hit = 0; j = 6 } else { j = j + 1 } } 204 if hit == 1 { 205 // does the text after this occurrence (bounded to the literal) name our stem? 206 var q: i64 = i + 6 207 var lim: i64 = q + 300 208 if lim > sn { lim = sn } 209 var mention: i64 = 0 210 while q + stl <= lim { 211 var k: i64 = 0 212 var m2: i64 = 1 213 while k < stl { if sb[q+k] != stem[k] { m2 = 0; k = stl } else { k = k + 1 } } 214 if m2 == 1 { mention = 1; q = lim } else { q = q + 1 } 215 } 216 if mention == 1 { found = i + 6; i = sn } else { i = i + 1 } 217 } else { i = i + 1 } 218 } 219 if found < 0 { return 0 } 220 var p: i64 = found 221 var go: i64 = 1 222 while go == 1 { if p < sn { if sb[p] == (32 as u8) { p = p + 1 } else { go = 0 } } else { go = 0 } } 223 var o: i64 = 0 224 var lastsp: i64 = 0 225 var scan: i64 = 1 226 while scan == 1 { 227 if p >= sn { scan = 0 } else { 228 var c: i64 = sb[p] as i64 229 if c == 34 { scan = 0 } 230 if c == 10 { scan = 0 } 231 if c == 92 { if p + 1 < sn { if sb[p+1] == (110 as u8) { scan = 0 } } } 232 if scan == 1 { 233 if c < 32 { c = 32 } 234 if c == 9 { c = 32 } 235 if c == 32 { 236 if lastsp == 0 { if o < TG_GRAMCAP - 1 { out[o] = c as u8; o = o + 1 } } 237 lastsp = 1 238 } else { 239 lastsp = 0 240 if o < TG_GRAMCAP - 1 { out[o] = c as u8; o = o + 1 } 241 } 242 p = p + 1 243 } 244 } 245 } 246 var tc: i64 = 1 247 while tc == 1 { if o > 0 { if out[o-1] == (32 as u8) { o = o - 1 } else { tc = 0 } } else { tc = 0 } } 248 out[o] = 0 as u8 249 if o < TG_MINGRAM { return 0 } 250 return o 251} 252 253static TG_FROM_ARGLESS: i64 = 0 254static TG_FROM_PINNED: i64 = 0 255static TG_FROM_ARITY: i64 = 0 256 257// PASS 4 (2026-08-07): ARITY from the source's own argv[] references, for organs that document nothing. 258// WHY: sampling the organs still blank showed they take POSITIONAL arguments, not verbs -- 259// nx_atlas_prov reads `argv[1]`, nx_atlas_dedup reads `argv[1]` and `argv[2]`. There is no verb table to 260// harvest, which is exactly why three passes of text-harvesting found nothing. But the ARITY is a hard 261// structural fact sitting in the code: the highest index the source dereferences. 262// ★ WHEN A SOURCE DOCUMENTS NOTHING, IT STILL DECLARES ITS SHAPE -- COUNT WHAT IT READS. 263// An agent told "takes 2 positional arguments" is far better placed than one told nothing, even without 264// names. DERIVED, so the row says so and is counted separately. 265// Honest limits, declared: this is a LOWER BOUND (a loop over argv, or argv passed to a helper, is not 266// counted) and it says nothing about what the arguments MEAN. It is the floor, not the contract. 267func tg_max_argv(path: *u8) -> i64 { 268 let fd: i64 = sys_openat_rd(path) 269 if fd < 0 { return 0 - 1 } 270 let sb: *u8 = sys_mmap(TG_SRCCAP) 271 let sn: i64 = sys_read(fd, sb, TG_SRCCAP - 1) 272 sys_close(fd) 273 if sn <= 6 { return 0 - 1 } 274 var best: i64 = 0 275 var i: i64 = 0 276 while i + 6 <= sn { 277 var hit: i64 = 1 278 if sb[i] != (97 as u8) { hit = 0 } 279 if hit == 1 { if sb[i+1] != (114 as u8) { hit = 0 } } 280 if hit == 1 { if sb[i+2] != (103 as u8) { hit = 0 } } 281 if hit == 1 { if sb[i+3] != (118 as u8) { hit = 0 } } 282 if hit == 1 { if sb[i+4] != (91 as u8) { hit = 0 } } 283 if hit == 1 { 284 var p: i64 = i + 5 285 var v: i64 = 0 - 1 286 while p < sn { 287 let c: i64 = sb[p] as i64 288 if c >= 48 { if c <= 57 { if v < 0 { v = 0 } v = v * 10 + (c - 48); p = p + 1 } else { p = sn } } else { p = sn } 289 } 290 if v > best { if v < 64 { best = v } } 291 } 292 i = i + 1 293 } 294 return best 295} 296 297// PASS 0 -- PINNED ROWS OVERRIDE EVERYTHING (2026-08-07). A tool_allowlist.conf row may carry PINNED ARGS 298// after the GREEN column (`nx_status <TAB> nx_hostctl <TAB> GREEN <TAB> status`). For such a row the 299// registry supplies the argv and the CALLER'S argv IS IGNORED -- that is the whole point (zero hostile-arg 300// surface). MEASURED: 58 of 872 rows (6.7%) are pinned, and 44 of them were being served a grammar 301// harvested from the underlying ELF -- e.g. nx_session_mint advertising 302// `<keysfile> <realm> <handle> <ttl_s>` that a caller CANNOT pass, and nx_status/nx_health inheriting 303// nx_hostctl's / nx_mgmt_call's arguments. Telling an agent to pass arguments that are silently discarded 304// is worse than telling it nothing: it invites a call that looks accepted and does something else. 305// ★★ FOR A PINNED ROW THE ELF'S OWN GRAMMAR IS A LIE TO THE CALLER -- THE CONTRACT BELONGS TO THE ROW, 306// NOT TO THE BINARY. So this runs FIRST and wins over every harvested source. 307// FOUND BY A SECOND INSTRUMENT: mining 2.8 GB of session transcripts showed nx_status (515 calls), 308// nx_health (456), nx_services (65) and nx_torstat (24) are ALWAYS invoked with zero arguments, which no 309// static read of their ELF could ever have revealed -- the ELF genuinely takes args, the ROW pins them. 310// ★★★★★ TWO INSTRUMENTS THAT DISAGREE LOCATE A DEFECT NEITHER COULD FIND ALONE. 311// Returns pinned-arg length written to out, or 0 if this row is not pinned. 312func tg_pinned_args(al: *u8, ls: i64, le: i64, out: *u8) -> i64 { 313 var fi: i64 = 0 314 var s: i64 = ls 315 var i: i64 = ls 316 var ps: i64 = 0 - 1 317 while i <= le { 318 var sep: i64 = 0 319 if i == le { sep = 1 } else { if al[i] == (9 as u8) { sep = 1 } } 320 if sep == 1 { 321 if fi == 3 { ps = s; i = le } 322 fi = fi + 1 323 s = i + 1 324 } 325 i = i + 1 326 } 327 if ps < 0 { return 0 } 328 var o: i64 = 0 329 var lastsp: i64 = 0 330 var q: i64 = ps 331 while q < le { 332 var c: i64 = al[q] as i64 333 if c < 32 { c = 32 } 334 if c == 9 { c = 32 } 335 if c == 32 { 336 if lastsp == 0 { if o < TG_GRAMCAP - 1 { out[o] = c as u8; o = o + 1 } } 337 lastsp = 1 338 } else { 339 lastsp = 0 340 if o < TG_GRAMCAP - 1 { out[o] = c as u8; o = o + 1 } 341 } 342 q = q + 1 343 } 344 var tc: i64 = 1 345 while tc == 1 { if o > 0 { if out[o-1] == (32 as u8) { o = o - 1 } else { tc = 0 } } else { tc = 0 } } 346 out[o] = 0 as u8 347 return o 348} 349 350// PASS 3 (2026-08-07): is this organ ARGLESS BY CONSTRUCTION? NishiLang gives a structural answer -- 351// `func main() -> i64` cannot reach argv at all, while `func main(argc: i64, argv: *i64)` can. MEASURED 352// across the tree: 2,058 sources take no params, 1,777 take argc/argv, so the signal is real and it 353// discriminates. 354// WHY THIS MATTERS MORE THAN MORE HARVESTING: of 369 tools with no contract, 182 (49.3%) are `*_gate` and 355// most of the rest are pinned or HTTP-backed -- they take NO arguments, so an empty grammar was the 356// CORRECT answer and further harvesting could never have found one. The real defect was that an agent 357// reading a blank cell cannot tell UNDOCUMENTED from TAKES-NOTHING. 358// ★ SILENCE IS NOT AN ANSWER: "no contract" and "no arguments" are different facts and must not share a 359// representation. Turning the second into a definitive statement is worth more than guessing at the first. 360// HONESTY: unlike passes 1 and 2 this string is DERIVED, not verbatim source text, so it SAYS SO in the row 361// itself and is counted separately (from_argless_signature) -- a reader can always subtract it. 362// Returns 1 argless, 0 takes-args, -1 unknown/unreadable (never guessed). 363func tg_is_argless(path: *u8) -> i64 { 364 let fd: i64 = sys_openat_rd(path) 365 if fd < 0 { return 0 - 1 } 366 let sb: *u8 = sys_mmap(TG_SRCCAP) 367 let sn: i64 = sys_read(fd, sb, TG_SRCCAP - 1) 368 sys_close(fd) 369 if sn <= 10 { return 0 - 1 } 370 let ndl: *u8 = "func main(" as *u8 371 var i: i64 = 0 372 while i + 10 <= sn { 373 var j: i64 = 0 374 var hit: i64 = 1 375 while j < 10 { if sb[i+j] != ndl[j] { hit = 0; j = 10 } else { j = j + 1 } } 376 if hit == 1 { 377 if sb[i+10] == (41 as u8) { return 1 } 378 return 0 379 } 380 i = i + 1 381 } 382 return 0 - 1 383} 384 385func main() -> i64 { 386 let al: *u8 = sys_mmap(TG_ALCAP) 387 let fd: i64 = sys_openat_rd("tool_allowlist.conf" as *u8) 388 if fd < 0 { tgw("{\"organ\":\"nx_toolgrammar\",\"refused\":\"tool_allowlist.conf unreadable\"}\n" as *u8); sys_exit(2); return 2 } 389 let n: i64 = sys_read(fd, al, TG_ALCAP - 1) 390 sys_close(fd) 391 if n <= 0 { tgw("{\"organ\":\"nx_toolgrammar\",\"refused\":\"tool_allowlist.conf empty\"}\n" as *u8); sys_exit(2); return 2 } 392 if n >= TG_ALCAP - 1 { tgw("{\"organ\":\"nx_toolgrammar\",\"refused\":\"allowlist read filled the buffer (possible truncation) -- refusing a partial census\"}\n" as *u8); sys_exit(2); return 2 } 393 al[n] = 0 as u8 394 395 // idempotent by construction: the derived file is rebuilt whole, never appended to across runs 396 sys_unlinkat(TG_OUT) 397 let of: i64 = sys_openat_append(TG_OUT, 420) 398 if of < 0 { tgw("{\"organ\":\"nx_toolgrammar\",\"refused\":\"cannot create knowledge/tool_grammar.conf\"}\n" as *u8); sys_exit(2); return 2 } 399 ma_write_str(of, "# tool_grammar.conf -- DERIVED argv contracts, emitted by nx_toolgrammar from each organ's own\n" as *u8) 400 ma_write_str(of, "# source header (usage lines: a // comment indented 2-3 spaces carrying < [ or ->). Read by\n" as *u8) 401 ma_write_str(of, "# nx_tools_api ONLY when tool_schemas.conf col8 is absent -- an AUTHORED contract always wins.\n" as *u8) 402 ma_write_str(of, "# Regenerate any time: nx_toolgrammar. TAB-separated: <name>\\t<grammar>\n" as *u8) 403 404 var scanned: i64 = 0 405 var emitted: i64 = 0 406 var nosrc: i64 = 0 407 var nousage: i64 = 0 408 let nm: *u8 = sys_mmap(TG_NAMECAP) 409 let elf: *u8 = sys_mmap(TG_PATHCAP) 410 let gr: *u8 = sys_mmap(TG_GRAMCAP) 411 let pth: *u8 = sys_mmap(TG_PATHCAP) 412 var i: i64 = 0 413 while i < n { 414 var le: i64 = i 415 var sc: i64 = 1 416 while sc == 1 { if le >= n { sc = 0 } else { if al[le] == (10 as u8) { sc = 0 } else { le = le + 1 } } } 417 var ok: i64 = 1 418 if le <= i { ok = 0 } 419 if ok == 1 { if al[i] == (35 as u8) { ok = 0 } } 420 if ok == 1 { 421 var nmn: i64 = 0 422 var p: i64 = i 423 var s2: i64 = 1 424 while s2 == 1 { 425 if p >= le { s2 = 0; ok = 0 } else { 426 if al[p] == (9 as u8) { s2 = 0 } else { 427 if nmn < TG_NAMECAP - 1 { nm[nmn] = al[p]; nmn = nmn + 1 } 428 p = p + 1 429 } 430 } 431 } 432 nm[nmn] = 0 as u8 433 var en: i64 = 0 434 if ok == 1 { 435 p = p + 1 436 var s3: i64 = 1 437 while s3 == 1 { 438 if p >= le { s3 = 0 } else { 439 if al[p] == (9 as u8) { s3 = 0 } else { 440 if en < TG_PATHCAP - 1 { elf[en] = al[p]; en = en + 1 } 441 p = p + 1 442 } 443 } 444 } 445 } 446 elf[en] = 0 as u8 447 if nmn == 0 { ok = 0 } 448 if en == 0 { ok = 0 } 449 if ok == 1 { 450 scanned = scanned + 1 451 // stem = the elf basename with any staged/built suffix removed (same ladder as nx_schema_backfill) 452 var bs: i64 = 0 453 var k: i64 = 0 454 while elf[k] != (0 as u8) { if elf[k] == (47 as u8) { bs = k + 1 } k = k + 1 } 455 var stl: i64 = k - bs 456 let base: *u8 = ((elf as i64) + bs) as *u8 457 if tg_ends(base, stl, ".sov.elf.new" as *u8, 12) == 1 { stl = stl - 12 } else { 458 if tg_ends(base, stl, ".elf.new" as *u8, 8) == 1 { stl = stl - 8 } else { 459 if tg_ends(base, stl, ".sov.elf" as *u8, 8) == 1 { stl = stl - 8 } else { 460 if tg_ends(base, stl, ".elf" as *u8, 4) == 1 { stl = stl - 4 } else { 461 if tg_ends(base, stl, ".new" as *u8, 4) == 1 { stl = stl - 4 } 462 } 463 } 464 } 465 } 466 var gn: i64 = 0 467 var r1: i64 = 0 - 1 468 // PASS 0: pinned row wins outright -- the caller's argv is discarded, so no harvested 469 // grammar from the underlying ELF may be published for this tool. 470 let pinbuf: *u8 = sys_mmap(TG_GRAMCAP) 471 let pn: i64 = tg_pinned_args(al, i, le, pinbuf) 472 if pn > 0 { 473 var po: i64 = sd_cat(gr, 0, "(no caller args -- PINNED row: the registry supplies `" as *u8) 474 var pc: i64 = 0 475 while pc < pn { if po < TG_GRAMCAP - 3 { gr[po] = pinbuf[pc]; po = po + 1 } pc = pc + 1 } 476 po = sd_cat(gr, po, "` and your argv is ignored)" as *u8) 477 gr[po] = 0 as u8 478 gn = po 479 TG_FROM_PINNED = TG_FROM_PINNED + 1 480 } 481 if gn == 0 { 482 if stl > 0 { 483 var o2: i64 = sd_cat(pth, 0, "buildroot/runtime/_hdl_build/" as *u8) 484 var c2: i64 = 0 485 while c2 < stl { pth[o2] = base[c2]; o2 = o2 + 1; c2 = c2 + 1 } 486 o2 = sd_cat(pth, o2, ".nx" as *u8) 487 pth[o2] = 0 as u8 488 r1 = tg_grammar_from_header(pth, gr) 489 if r1 > 0 { gn = r1 } else { 490 o2 = sd_cat(pth, 0, "buildroot/runtime/" as *u8) 491 c2 = 0 492 while c2 < stl { pth[o2] = base[c2]; o2 = o2 + 1; c2 = c2 + 1 } 493 o2 = sd_cat(pth, o2, ".nx" as *u8) 494 pth[o2] = 0 as u8 495 let r2: i64 = tg_grammar_from_header(pth, gr) 496 if r2 > 0 { gn = r2 } else { if r2 == 0 { r1 = 0 } } 497 } 498 } 499 if gn > 0 { TG_FROM_HEADER = TG_FROM_HEADER + 1 } 500 } 501 // PASS 2: only when the header convention yielded nothing. Header wins by construction. 502 if gn == 0 { 503 if stl > 0 { 504 var o3: i64 = sd_cat(pth, 0, "buildroot/runtime/_hdl_build/" as *u8) 505 var c4: i64 = 0 506 while c4 < stl { pth[o3] = base[c4]; o3 = o3 + 1; c4 = c4 + 1 } 507 o3 = sd_cat(pth, o3, ".nx" as *u8) 508 pth[o3] = 0 as u8 509 var u1: i64 = tg_usage_literal(pth, gr, nm, nmn) 510 if u1 <= 0 { 511 o3 = sd_cat(pth, 0, "buildroot/runtime/" as *u8) 512 c4 = 0 513 while c4 < stl { pth[o3] = base[c4]; o3 = o3 + 1; c4 = c4 + 1 } 514 o3 = sd_cat(pth, o3, ".nx" as *u8) 515 pth[o3] = 0 as u8 516 u1 = tg_usage_literal(pth, gr, nm, nmn) 517 } 518 if u1 > 0 { gn = u1; TG_FROM_USAGE = TG_FROM_USAGE + 1 } 519 } 520 } 521 // PASS 3: still nothing -- is it argless BY SIGNATURE? Say so definitively. 522 if gn == 0 { 523 if stl > 0 { 524 var o5: i64 = sd_cat(pth, 0, "buildroot/runtime/_hdl_build/" as *u8) 525 var c6: i64 = 0 526 while c6 < stl { pth[o5] = base[c6]; o5 = o5 + 1; c6 = c6 + 1 } 527 o5 = sd_cat(pth, o5, ".nx" as *u8) 528 pth[o5] = 0 as u8 529 var al1: i64 = tg_is_argless(pth) 530 if al1 < 0 { 531 o5 = sd_cat(pth, 0, "buildroot/runtime/" as *u8) 532 c6 = 0 533 while c6 < stl { pth[o5] = base[c6]; o5 = o5 + 1; c6 = c6 + 1 } 534 o5 = sd_cat(pth, o5, ".nx" as *u8) 535 pth[o5] = 0 as u8 536 al1 = tg_is_argless(pth) 537 } 538 if al1 == 1 { 539 gn = sd_cat(gr, 0, "(no args -- DERIVED: this organ's main() takes no argv, so it cannot read arguments)" as *u8) 540 gr[gn] = 0 as u8 541 TG_FROM_ARGLESS = TG_FROM_ARGLESS + 1 542 } 543 } 544 } 545 // PASS 4: documents nothing, but the source still declares its SHAPE. 546 if gn == 0 { 547 if stl > 0 { 548 var o7: i64 = sd_cat(pth, 0, "buildroot/runtime/_hdl_build/" as *u8) 549 var c8: i64 = 0 550 while c8 < stl { pth[o7] = base[c8]; o7 = o7 + 1; c8 = c8 + 1 } 551 o7 = sd_cat(pth, o7, ".nx" as *u8) 552 pth[o7] = 0 as u8 553 var mx: i64 = tg_max_argv(pth) 554 if mx <= 0 { 555 o7 = sd_cat(pth, 0, "buildroot/runtime/" as *u8) 556 c8 = 0 557 while c8 < stl { pth[o7] = base[c8]; o7 = o7 + 1; c8 = c8 + 1 } 558 o7 = sd_cat(pth, o7, ".nx" as *u8) 559 pth[o7] = 0 as u8 560 mx = tg_max_argv(pth) 561 } 562 if mx > 0 { 563 var ao: i64 = sd_cat(gr, 0, "(takes at least " as *u8) 564 var dg: i64 = mx 565 if dg > 9 { gr[ao] = ((48 + (dg / 10)) as u8); ao = ao + 1; dg = dg - ((dg / 10) * 10) } 566 gr[ao] = ((48 + dg) as u8); ao = ao + 1 567 ao = sd_cat(gr, ao, " positional argument(s) -- DERIVED: the source dereferences argv up to this index; a LOWER BOUND, and their meanings are undocumented)" as *u8) 568 gr[ao] = 0 as u8 569 gn = ao 570 TG_FROM_ARITY = TG_FROM_ARITY + 1 571 } 572 } 573 } 574 if gn > 0 { 575 ma_write_str(of, nm) 576 ma_write_str(of, "\t" as *u8) 577 sys_write(of, gr, gn) 578 ma_write_str(of, "\n" as *u8) 579 emitted = emitted + 1 580 } else { 581 if r1 < 0 { nosrc = nosrc + 1 } else { nousage = nousage + 1 } 582 } 583 } 584 } 585 i = le + 1 586 } 587 sys_close(of) 588 589 tgw("{\"organ\":\"nx_toolgrammar\",\"out\":\"knowledge/tool_grammar.conf\",\"scanned\":" as *u8); tgn(scanned) 590 tgw(",\"emitted\":" as *u8); tgn(emitted) 591 tgw(",\"skipped_no_source\":" as *u8); tgn(nosrc) 592 tgw(",\"skipped_no_usage_line\":" as *u8); tgn(nousage) 593 tgw(",\"prose_lines_rejected\":" as *u8); tgn(TG_REJECTED) 594 tgw(",\"from_header_convention\":" as *u8); tgn(TG_FROM_HEADER) 595 tgw(",\"from_usage_literal\":" as *u8); tgn(TG_FROM_USAGE) 596 tgw(",\"from_argless_signature\":" as *u8); tgn(TG_FROM_ARGLESS) 597 tgw(",\"from_pinned_row\":" as *u8); tgn(TG_FROM_PINNED) 598 tgw(",\"from_argv_arity\":" as *u8); tgn(TG_FROM_ARITY) 599 tgw(",\"note\":\"PROVENANCE RULE (stated as a RULE, not a list -- an enumerated note goes stale every time a source is added, which it did three times). EXACTLY TWO counters are VERBATIM source text: from_header_convention and from_usage_literal. EVERY OTHER from_* counter is DERIVED, and every derived row SAYS SO inside its own text, so a reader can always tell them apart without consulting this note. HARVESTED-ONLY coverage = from_header_convention + from_usage_literal. Precedence: authored tool_schemas.conf col8 > pinned row > verbatim harvest > derived.\"}\n" as *u8) 600 sys_exit(0) 601 return 0 602}