code wiki / _hdl_build / nx_schema_backfill.nx
nx_schema_backfill.nx source
↩ module page · 240 lines · 11403 B
1// nx_schema_backfill.nx -- CAPABILITY DISCOVERABILITY HARVESTER (seq1282). Every tool_allowlist.conf row
2// lacking a knowledge/tool_schemas.conf row gets one AUTO-DERIVED from its source's own first header line
3// (the tree-wide `// <stem>.nx -- <desc>` convention; the codewiki maker beat writes missing headers daily,
4// so RE-RUNNING harvests newly documented organs). The register API keeps NEW tools discoverable by
5// construction (seq722 fix) -- this organ only drains history. HONEST: no source / no `-- ` header / desc
6// too short => SKIPPED + COUNTED, never guessed (blank beats bad). Append-if-absent via the API's own
7// ma_schema_has_name tri-state (UNKNOWN refuses the WHOLE run -- a truncated read can never duplicate).
8// nx_schema_backfill (JSON report: scanned/had_schema/filled/skipped_no_source/skipped_no_header)
9// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
10import "nx_mgmt_api.nx"
11import "nx_syscalls.nx"
12
13// sized: allowlist read matches md_allow_has_name's 256KiB envelope; refuse-on-full keeps the census honest
14const SB_ALCAP: i64 = 1 << 18
15// sized: only the FIRST source line is read; header docs are one-liners
16const SB_HDRCAP: i64 = 4096
17// sized: schema titles are one-line prose; hard cap keeps rows lean
18const SB_TITLECAP: i64 = 300
19// derived: shortest honest capability description in curated rows is ~20 bytes; below = not a title, skip
20const SB_MINDESC: i64 = 20
21// sized: tool names are sanitized [a-zA-Z0-9_] <= 120 by the register API
22const SB_NAMECAP: i64 = 128
23// sized: elf paths in the allowlist are absolute NAS paths well under this
24const SB_PATHCAP: i64 = 512
25
26func sbw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
27
28func sb_ends(s: *u8, sl: i64, suf: *u8, fl: i64) -> i64 {
29 if sl < fl { return 0 }
30 var i: i64 = 0
31 while i < fl { if s[sl-fl+i] != suf[i] { return 0 } i = i + 1 }
32 return 1
33}
34
35// append one schema row -- SAME invariants as the API path (trailing-nl self-heal; caller scrubbed title)
36func sb_append(nm: *u8, ti: *u8) -> i64 {
37 let sf: i64 = sys_openat_append("knowledge/tool_schemas.conf" as *u8, 420)
38 if sf < 0 { return 0 }
39 ma_ensure_trailing_nl("knowledge/tool_schemas.conf" as *u8, sf)
40 ma_write_str(sf, nm)
41 ma_write_str(sf, "\t" as *u8)
42 ma_write_str(sf, ti)
43 ma_write_str(sf, "\t0\t1\t0\t1\t" as *u8)
44 ma_write_str(sf, nm)
45 ma_write_str(sf, " output (auto-derived from source header by nx_schema_backfill)\n" as *u8)
46 sys_close(sf)
47 return 1
48}
49
50// read the FIRST line of path; copy the text after the first `-- ` into ti (scrubbed, trimmed, capped).
51// returns title length; 0 = header convention absent or desc too short; -1 = file unreadable.
52func sb_title_from_header(path: *u8, ti: *u8) -> i64 {
53 let fd: i64 = sys_openat_rd(path)
54 if fd < 0 { return 0 - 1 }
55 let hb: *u8 = sys_mmap(SB_HDRCAP)
56 let hn: i64 = sys_read(fd, hb, SB_HDRCAP - 1)
57 sys_close(fd)
58 if hn <= 2 { return 0 }
59 // The header is NOT always line 1: many organs open with their `import` lines and put the
60 // `// <stem>.nx -- <desc>` block AFTER them (measured: nx_gamebench_gate, nx_media_extract_gate
61 // were reported as UNDOCUMENTED purely because this parser only looked at line 1 -- the organs were
62 // documented all along). Scan the header window for the FIRST `//` line carrying `-- `; that is the
63 // convention's actual shape. Declared limitation: a `//` line containing `-- ` above the real header
64 // would win, so the rule is first-match and the emitted title is always verbatim source text.
65 var ls: i64 = 0
66 var ds: i64 = 0
67 var le: i64 = 0
68 var scan: i64 = 1
69 while scan == 1 {
70 if ls >= hn { scan = 0 } else {
71 le = ls
72 var sc: i64 = 1
73 while sc == 1 { if le >= hn { sc = 0 } else { if hb[le] == (10 as u8) { sc = 0 } else { le = le + 1 } } }
74 var iscmt: i64 = 0
75 if le - ls >= 8 { if hb[ls] == (47 as u8) { if hb[ls+1] == (47 as u8) { iscmt = 1 } } }
76 if iscmt == 1 {
77 var p: i64 = ls + 2
78 var s2: i64 = 1
79 while s2 == 1 {
80 if p + 3 > le { s2 = 0 } else {
81 if hb[p] == (45 as u8) { if hb[p+1] == (45 as u8) { if hb[p+2] == (32 as u8) { ds = p + 3; s2 = 0 } } }
82 if ds == 0 { p = p + 1 }
83 }
84 }
85 }
86 if ds > 0 { scan = 0 } else { ls = le + 1 }
87 }
88 }
89 if ds == 0 { return 0 }
90 var o: i64 = 0
91 var q: i64 = ds
92 while q < le {
93 var c: i64 = hb[q] as i64
94 if c < 32 { c = 32 }
95 if c == 9 { c = 32 }
96 if o < SB_TITLECAP - 1 { ti[o] = c as u8; o = o + 1 }
97 q = q + 1
98 }
99 var tc: i64 = 1
100 while tc == 1 { if o > 0 { if ti[o-1] == (32 as u8) { o = o - 1 } else { tc = 0 } } else { tc = 0 } }
101 ti[o] = 0 as u8
102 if o < SB_MINDESC { return 0 }
103 return o
104}
105
106func main() -> i64 {
107 let al: *u8 = sys_mmap(SB_ALCAP)
108 let fd: i64 = sys_openat_rd("tool_allowlist.conf" as *u8)
109 if fd < 0 { sbw("{\"organ\":\"nx_schema_backfill\",\"refused\":\"tool_allowlist.conf unreadable\"}\n" as *u8); sys_exit(2); return 2 }
110 let n: i64 = sys_read(fd, al, SB_ALCAP - 1)
111 sys_close(fd)
112 if n <= 0 { sbw("{\"organ\":\"nx_schema_backfill\",\"refused\":\"tool_allowlist.conf empty\"}\n" as *u8); sys_exit(2); return 2 }
113 if n >= SB_ALCAP - 1 { sbw("{\"organ\":\"nx_schema_backfill\",\"refused\":\"allowlist read filled the buffer (possible truncation) -- refusing a partial census\"}\n" as *u8); sys_exit(2); return 2 }
114 al[n] = 0 as u8
115 var scanned: i64 = 0
116 var had: i64 = 0
117 var filled: i64 = 0
118 var nosrc: i64 = 0
119 var nohdr: i64 = 0
120 let nm: *u8 = sys_mmap(SB_NAMECAP)
121 let elf: *u8 = sys_mmap(SB_PATHCAP)
122 let ti: *u8 = sys_mmap(SB_TITLECAP)
123 let pth: *u8 = sys_mmap(SB_PATHCAP)
124 var i: i64 = 0
125 while i < n {
126 var le: i64 = i
127 var sc: i64 = 1
128 while sc == 1 { if le >= n { sc = 0 } else { if al[le] == (10 as u8) { sc = 0 } else { le = le + 1 } } }
129 var ok: i64 = 1
130 if le <= i { ok = 0 }
131 if ok == 1 { if al[i] == (35 as u8) { ok = 0 } }
132 if ok == 1 {
133 var nmn: i64 = 0
134 var p: i64 = i
135 var s2: i64 = 1
136 while s2 == 1 {
137 if p >= le { s2 = 0; ok = 0 } else {
138 if al[p] == (9 as u8) { s2 = 0 } else {
139 if nmn < SB_NAMECAP - 1 { nm[nmn] = al[p]; nmn = nmn + 1 }
140 p = p + 1
141 }
142 }
143 }
144 nm[nmn] = 0 as u8
145 var en: i64 = 0
146 if ok == 1 {
147 p = p + 1
148 var s3: i64 = 1
149 while s3 == 1 {
150 if p >= le { s3 = 0 } else {
151 if al[p] == (9 as u8) { s3 = 0 } else {
152 if en < SB_PATHCAP - 1 { elf[en] = al[p]; en = en + 1 }
153 p = p + 1
154 }
155 }
156 }
157 }
158 elf[en] = 0 as u8
159 if nmn == 0 { ok = 0 }
160 if en == 0 { ok = 0 }
161 if ok == 1 {
162 scanned = scanned + 1
163 let hs: i64 = ma_schema_has_name(nm)
164 if hs == 1 { had = had + 1 }
165 if hs < 0 {
166 sbw("{\"organ\":\"nx_schema_backfill\",\"refused\":\"tool_schemas.conf unreadable or possibly truncated -- refusing to append blind\"}\n" as *u8)
167 sys_exit(3)
168 return 3
169 }
170 if hs == 0 {
171 var bs: i64 = 0
172 var k: i64 = 0
173 while elf[k] != (0 as u8) { if elf[k] == (47 as u8) { bs = k + 1 } k = k + 1 }
174 var stl: i64 = k - bs
175 let base: *u8 = ((elf as i64) + bs) as *u8
176 if sb_ends(base, stl, ".sov.elf.new" as *u8, 12) == 1 { stl = stl - 12 } else {
177 if sb_ends(base, stl, ".elf.new" as *u8, 8) == 1 { stl = stl - 8 } else {
178 if sb_ends(base, stl, ".sov.elf" as *u8, 8) == 1 { stl = stl - 8 } else {
179 if sb_ends(base, stl, ".elf" as *u8, 4) == 1 { stl = stl - 4 } else {
180 if sb_ends(base, stl, ".new" as *u8, 4) == 1 { stl = stl - 4 }
181 }
182 }
183 }
184 }
185 var r1: i64 = 0 - 1
186 var r2: i64 = 0 - 1
187 var tin: i64 = 0
188 if stl > 0 {
189 var o2: i64 = sd_cat(pth, 0, "buildroot/runtime/_hdl_build/" as *u8)
190 var c2: i64 = 0
191 while c2 < stl { pth[o2] = base[c2]; o2 = o2 + 1; c2 = c2 + 1 }
192 o2 = sd_cat(pth, o2, ".nx" as *u8)
193 pth[o2] = 0 as u8
194 r1 = sb_title_from_header(pth, ti)
195 if r1 > 0 { tin = r1 } else {
196 o2 = sd_cat(pth, 0, "buildroot/runtime/" as *u8)
197 c2 = 0
198 while c2 < stl { pth[o2] = base[c2]; o2 = o2 + 1; c2 = c2 + 1 }
199 o2 = sd_cat(pth, o2, ".nx" as *u8)
200 pth[o2] = 0 as u8
201 r2 = sb_title_from_header(pth, ti)
202 if r2 > 0 { tin = r2 }
203 }
204 }
205 if tin > 0 {
206 if sb_append(nm, ti) == 1 { filled = filled + 1 }
207 } else {
208 var nof: i64 = 1
209 if r1 >= 0 { nof = 0 }
210 if r2 >= 0 { nof = 0 }
211 // a COUNT is not a work item: name every skip on stderr so the residual is
212 // actionable (write the header, re-run, watch the number fall) instead of
213 // being an unfalsifiable "2 left" that nobody can pick up.
214 sys_write(2, "SKIP " as *u8, 5)
215 if nof == 1 { sys_write(2, "no-source " as *u8, 12) } else { sys_write(2, "no-header " as *u8, 12) }
216 sys_write(2, nm, nmn)
217 sys_write(2, "\n" as *u8, 1)
218 if nof == 1 { nosrc = nosrc + 1 } else { nohdr = nohdr + 1 }
219 }
220 }
221 }
222 }
223 i = le + 1
224 }
225 let out: *u8 = sys_mmap(SB_HDRCAP)
226 var o3: i64 = sd_cat(out, 0, "{\"organ\":\"nx_schema_backfill\",\"scanned\":" as *u8)
227 o3 = sd_catn(out, o3, scanned)
228 o3 = sd_cat(out, o3, ",\"had_schema\":" as *u8)
229 o3 = sd_catn(out, o3, had)
230 o3 = sd_cat(out, o3, ",\"filled\":" as *u8)
231 o3 = sd_catn(out, o3, filled)
232 o3 = sd_cat(out, o3, ",\"skipped_no_source\":" as *u8)
233 o3 = sd_catn(out, o3, nosrc)
234 o3 = sd_cat(out, o3, ",\"skipped_no_header\":" as *u8)
235 o3 = sd_catn(out, o3, nohdr)
236 o3 = sd_cat(out, o3, ",\"note\":\"idempotent; re-run after maker-beat header writes; run nx_toolreg_reconcile to publish\"}\n" as *u8)
237 out[o3] = 0 as u8
238 sbw(out)
239 return 0
240}