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}