nx_pipeline_walker.nx source
↩ module page · 456 lines · 20313 B
1// nx_pipeline_walker.nx -- V2.0 P-1 pipeline-walker (Cardinal B FIRST goal).
2//
3// Walks operator-supplied artifact paths; reads each file via sys_read_file;
4// parses the V5 living-docs 6-field taxonomy (Quadrant / Topic Type / Status /
5// Trust State / Competitive State + Composes count); populates NxArtifactStore;
6// derives pipeline_stage per V2_0_PIPELINE_BOOTSTRAP_ARC_PLAN ยง2.0 mapping.
7//
8// COMPOSES (zero new parsers; ZERO bash + sed; per operator "from zero
9// everything nishi" cardinal):
10// wiki/nx_artifact_store (NxArtifactStore data model)
11// nx_html_extract (nx_he_match_ci case-insensitive byte match)
12// nx_search_inverted (nx_inv_hash_bytes_lower)
13// nx_syscalls (sys_read_file)
14//
15// COMPOSED BY:
16// wiki/nx_pipeline_route.nx (P-3 queued; renders this store)
17// wiki/nx_wiki_main.nx (P-5; startup integration)
18//
19// Per operator cardinal 2026-05-27: the V5 living-docs system already
20// exists at nxc2/docs/dashboards/* with bash + sed scaffolding. This
21// walker is the BITS-UP NishiLang replacement for the taxonomy-extraction
22// step (taxonomy parse + pipeline-stage derive). The bash pre-commit
23// rebuilder is queued for nx_git_hook + nx_markdown_render replacement
24// in a follow-on commit.
25//
26// V2.0 SCOPE:
27// - Per-artifact: sys_read_file -> parse 6-field front-matter ->
28// populate NxArtifactStore -> derive stage
29// - Bounded by NX_PWALK_MAX_BYTES_PER_FILE
30// - Skips files larger than cap (rare; flagged as EXEMPT_TOO_LARGE)
31//
32// V2.5+ SCOPE (TODO):
33// - sys_getdents recursive walker (V2.0 takes operator-supplied path list)
34// - nx_git_hook sovereign replacement for pre-commit bash
35// - Incremental walk (only re-process changed files; content-hash diff)
36//
37// Status: V2.0. 2026-05-27.
38
39import "nx_syscalls.nx"
40import "nx_html_extract.nx"
41import "nx_search_inverted.nx"
42import "wiki/nx_artifact_store.nx"
43import "hub/nx_doc_extractor_nx.nx"
44import "hub/nx_doc_extractor_md.nx"
45
46// ===== Sealed verdict surface (codes 2950-2969) =================================================
47const NX_PWALK_OK: i64 = 0
48const NX_PWALK_BAD_INPUT: i64 = 2950
49const NX_PWALK_READ_FAILED: i64 = 2951
50const NX_PWALK_FILE_TOO_LARGE: i64 = 2952
51const NX_PWALK_STORE_OVERFLOW: i64 = 2953
52const NX_PWALK_LOOP_BUDGET: i64 = 2954
53const NX_PWALK_PARSE_FAILED: i64 = 2955
54
55// ===== Named constants (M7) =================================================
56const NX_PWALK_MAX_BYTES_PER_FILE: i64 = 1048576 // 1 MB scan cap
57const NX_PWALK_HEAD_SCAN_LIMIT: i64 = 16384 // front-matter in first 16 KB
58const NX_PWALK_LOOP_BUDGET_CAP: i64 = 10000000
59
60// ASCII (M7)
61const NX_PWALK_ASCII_NL: i64 = 0x0A // '\n'
62const NX_PWALK_ASCII_COLON: i64 = 0x3A // ':'
63const NX_PWALK_ASCII_OPEN: i64 = 0x5B // '['
64const NX_PWALK_ASCII_CLOSE: i64 = 0x5D // ']'
65
66// ===== Find a "**Field:** value" line in front-matter =================================================
67//
68// Returns 1 + fills out_val_off/out_val_len if found; 0 otherwise.
69// Searches first NX_PWALK_HEAD_SCAN_LIMIT bytes; case-insensitive on
70// field name; skips leading "**" markdown bold markers.
71
72func nx_pwalk_find_field(src: *u8, src_n: i64,
73 field_z: *u8, field_n: i64,
74 out_val_off: *i64, out_val_len: *i64) -> i64 {
75 if (out_val_off as i64) == 0 { return 0 }
76 if (out_val_len as i64) == 0 { return 0 }
77 out_val_off[0] = 0
78 out_val_len[0] = 0
79 if src_n < 1 { return 0 }
80 var limit: i64 = src_n
81 if limit > NX_PWALK_HEAD_SCAN_LIMIT { limit = NX_PWALK_HEAD_SCAN_LIMIT }
82
83 var i: i64 = 0
84 var iter: i64 = 0
85 while i < limit {
86 if iter >= NX_PWALK_LOOP_BUDGET_CAP { return 0 }
87 iter = iter + 1
88 // Skip whitespace + leading markdown bold markers (`**`).
89 // We look for: optional **, field name, optional **, ':', value, newline.
90 var p: i64 = i
91 if p + 2 < limit {
92 if (src[p] as i64) == 0x2A { // '*'
93 if (src[p + 1] as i64) == 0x2A { p = p + 2 }
94 }
95 }
96 // Compare field name case-insensitively.
97 if nx_he_match_ci(src, p, src_n, field_z, field_n) == 1 {
98 let after_name: i64 = p + field_n
99 var q: i64 = after_name
100 // Optional closing **
101 if q + 1 < limit {
102 if (src[q] as i64) == 0x2A {
103 if (src[q + 1] as i64) == 0x2A { q = q + 2 }
104 }
105 }
106 // Expect ':' next (possibly preceded by whitespace).
107 while q < limit {
108 let c: i64 = src[q] as i64
109 if c == NX_PWALK_ASCII_COLON {
110 // Skip ':' + whitespace; capture until newline.
111 let val_start: i64 = q + 1
112 var v: i64 = val_start
113 while v < limit {
114 let cv: i64 = src[v] as i64
115 if cv != 0x20 { if cv != 0x09 { v = limit + 1 } }
116 if v <= limit { if v < limit { v = v + 1 } }
117 }
118 let real_v: i64 = if v > limit then limit else v - 1
119 // Walk to newline.
120 var e: i64 = real_v
121 while e < limit {
122 if (src[e] as i64) == NX_PWALK_ASCII_NL { e = limit + 1 }
123 if e <= limit { if e < limit { e = e + 1 } }
124 }
125 let real_e: i64 = if e > limit then limit else e - 1
126 out_val_off[0] = real_v
127 out_val_len[0] = real_e - real_v
128 return 1
129 }
130 if c == NX_PWALK_ASCII_NL { q = limit + 1 } // EOL before ':'; not this line
131 if q < limit { q = q + 1 }
132 }
133 }
134 // Skip to next line.
135 while i < limit {
136 if (src[i] as i64) == NX_PWALK_ASCII_NL { i = limit + 1 }
137 if i <= limit { if i < limit { i = i + 1 } }
138 }
139 if i > limit { i = limit }
140 i = i + 1
141 if i <= p { i = p + 1 }
142 }
143 return 0
144}
145
146// ===== Per-field value classifier (sealed-enum mapping) =================================================
147
148func nx_pwalk_classify_quadrant(src: *u8, off: i64, n: i64) -> i64 {
149 if n < 1 { return NX_ART_QUAD_NONE }
150 if nx_he_match_ci(src, off, off + n, "TUTORIAL" as *u8, 8) == 1 { return NX_ART_QUAD_TUTORIAL }
151 if nx_he_match_ci(src, off, off + n, "HOW-TO" as *u8, 6) == 1 { return NX_ART_QUAD_HOWTO }
152 if nx_he_match_ci(src, off, off + n, "HOWTO" as *u8, 5) == 1 { return NX_ART_QUAD_HOWTO }
153 if nx_he_match_ci(src, off, off + n, "REFERENCE" as *u8, 9) == 1 { return NX_ART_QUAD_REFERENCE }
154 if nx_he_match_ci(src, off, off + n, "EXPLANATION" as *u8, 11) == 1 { return NX_ART_QUAD_EXPLANATION }
155 return NX_ART_QUAD_NONE
156}
157
158func nx_pwalk_classify_topic_type(src: *u8, off: i64, n: i64) -> i64 {
159 if n < 1 { return NX_ART_DITA_NONE }
160 if nx_he_match_ci(src, off, off + n, "TASK" as *u8, 4) == 1 { return NX_ART_DITA_TASK }
161 if nx_he_match_ci(src, off, off + n, "CONCEPT" as *u8, 7) == 1 { return NX_ART_DITA_CONCEPT }
162 if nx_he_match_ci(src, off, off + n, "REFERENCE" as *u8, 9) == 1 { return NX_ART_DITA_REFERENCE }
163 if nx_he_match_ci(src, off, off + n, "GLOSSARY" as *u8, 8) == 1 { return NX_ART_DITA_GLOSSARY }
164 return NX_ART_DITA_NONE
165}
166
167func nx_pwalk_classify_status(src: *u8, off: i64, n: i64) -> i64 {
168 if n < 1 { return NX_ART_STATUS_NONE }
169 if nx_he_match_ci(src, off, off + n, "CANONICAL" as *u8, 9) == 1 { return NX_ART_STATUS_CANONICAL }
170 if nx_he_match_ci(src, off, off + n, "WIP" as *u8, 3) == 1 { return NX_ART_STATUS_WIP }
171 if nx_he_match_ci(src, off, off + n, "DEPRECATED" as *u8, 10) == 1 { return NX_ART_STATUS_DEPRECATED }
172 return NX_ART_STATUS_NONE
173}
174
175func nx_pwalk_classify_trust(src: *u8, off: i64, n: i64) -> i64 {
176 if n < 1 { return NX_ART_TRUST_NONE }
177 if nx_he_match_ci(src, off, off + n, "PERSONALLY_MEASURED" as *u8, 19) == 1 { return NX_ART_TRUST_PERSONALLY_MEASURED }
178 if nx_he_match_ci(src, off, off + n, "WEBSEARCH-VERIFIED" as *u8, 18) == 1 { return NX_ART_TRUST_WEBSEARCH_VERIFIED }
179 if nx_he_match_ci(src, off, off + n, "WEBSEARCH_VERIFIED" as *u8, 18) == 1 { return NX_ART_TRUST_WEBSEARCH_VERIFIED }
180 if nx_he_match_ci(src, off, off + n, "EXPERT-VERIFIED" as *u8, 15) == 1 { return NX_ART_TRUST_EXPERT_VERIFIED }
181 if nx_he_match_ci(src, off, off + n, "EXPERT_VERIFIED" as *u8, 15) == 1 { return NX_ART_TRUST_EXPERT_VERIFIED }
182 if nx_he_match_ci(src, off, off + n, "WRITTEN_UNTESTED" as *u8, 16) == 1 { return NX_ART_TRUST_WRITTEN_UNTESTED }
183 if nx_he_match_ci(src, off, off + n, "WRITTEN-UNTESTED" as *u8, 16) == 1 { return NX_ART_TRUST_WRITTEN_UNTESTED }
184 return NX_ART_TRUST_NONE
185}
186
187func nx_pwalk_classify_competitive(src: *u8, off: i64, n: i64) -> i64 {
188 if n < 1 { return NX_ART_COMP_NONE }
189 // Value formats per V5 doctrine: "BEATS_[INCUMBENT]" / "MATCHES_[INCUMBENT]" /
190 // "UNDER_[INCUMBENT]" / "UNCLASSIFIED" / "UNCLASSIFIED (reason)".
191 if nx_he_match_ci(src, off, off + n, "BEATS" as *u8, 5) == 1 { return NX_ART_COMP_BEATS }
192 if nx_he_match_ci(src, off, off + n, "MATCHES" as *u8, 7) == 1 { return NX_ART_COMP_MATCHES }
193 if nx_he_match_ci(src, off, off + n, "UNDER" as *u8, 5) == 1 { return NX_ART_COMP_UNDER }
194 if nx_he_match_ci(src, off, off + n, "UNCLASSIFIED" as *u8, 12) == 1 { return NX_ART_COMP_UNCLASSIFIED }
195 return NX_ART_COMP_NONE
196}
197
198// ===== Count [[X]] refs in body (composes V5 nx_doc_xref signal) =================================================
199//
200// Walks body bytes; counts '[[' tokens that close with ']]' within
201// NX_PWALK_MAX_BYTES_PER_FILE; bounded.
202
203func nx_pwalk_count_composes(src: *u8, src_n: i64) -> i64 {
204 if src_n < 4 { return 0 }
205 var count: i64 = 0
206 var i: i64 = 0
207 var iter: i64 = 0
208 while i + 3 < src_n {
209 if iter >= NX_PWALK_LOOP_BUDGET_CAP { return count }
210 iter = iter + 1
211 if (src[i] as i64) == NX_PWALK_ASCII_OPEN {
212 if (src[i + 1] as i64) == NX_PWALK_ASCII_OPEN {
213 // Find closing ]]
214 var j: i64 = i + 2
215 while j + 1 < src_n {
216 if (src[j] as i64) == NX_PWALK_ASCII_CLOSE {
217 if (src[j + 1] as i64) == NX_PWALK_ASCII_CLOSE {
218 count = count + 1
219 i = j + 1
220 j = src_n + 1
221 }
222 }
223 if j < src_n { j = j + 1 }
224 }
225 }
226 }
227 i = i + 1
228 }
229 return count
230}
231
232// ===== Count lines (for line_count stat) =================================================
233
234func nx_pwalk_count_lines(src: *u8, src_n: i64) -> i64 {
235 if src_n < 1 { return 0 }
236 var n: i64 = 1 // at least one line if any bytes
237 var i: i64 = 0
238 while i < src_n {
239 if (src[i] as i64) == NX_PWALK_ASCII_NL { n = n + 1 }
240 i = i + 1
241 }
242 return n
243}
244
245// ===== Classify artifact kind from path =================================================
246
247func nx_pwalk_classify_kind(path: *u8, path_n: i64) -> i64 {
248 if path_n < 1 { return NX_ART_KIND_UNKNOWN }
249 // _test.nx
250 if path_n > 8 {
251 if nx_he_match_ci(path, path_n - 8, path_n, "_test.nx" as *u8, 8) == 1 { return NX_ART_KIND_TEST_NX }
252 }
253 // .nx (runtime)
254 if path_n > 3 {
255 if nx_he_match_ci(path, path_n - 3, path_n, ".nx" as *u8, 3) == 1 {
256 // Distinguish silicon arcs by path prefix (heuristic).
257 if path_n > 7 {
258 if nx_he_match_ci(path, 0, path_n, "silicon" as *u8, 7) == 1 { return NX_ART_KIND_SILICON_ARC }
259 }
260 return NX_ART_KIND_RUNTIME_NX
261 }
262 }
263 // .sh (bench)
264 if path_n > 3 {
265 if nx_he_match_ci(path, path_n - 3, path_n, ".sh" as *u8, 3) == 1 { return NX_ART_KIND_BENCH_SH }
266 }
267 // .md classification by path heuristic
268 if path_n > 3 {
269 if nx_he_match_ci(path, path_n - 3, path_n, ".md" as *u8, 3) == 1 {
270 // dashboards/ -> DASHBOARD_MD
271 if nx_he_match_ci(path, 0, path_n, "nxc2/docs/dashboards/" as *u8, 21) == 1 { return NX_ART_KIND_DASHBOARD_MD }
272 // /memory/ -> MEMORY_MD
273 if nx_he_match_ci(path, 0, path_n, "memory/" as *u8, 7) == 1 { return NX_ART_KIND_MEMORY_MD }
274 // _DOCTRINE_ or _ROADMAP -> RFC_MD
275 // (simple substring match)
276 var i: i64 = 0
277 while i + 10 < path_n {
278 if nx_he_match_ci(path, i, path_n, "_DOCTRINE_" as *u8, 10) == 1 { return NX_ART_KIND_RFC_MD }
279 i = i + 1
280 }
281 // Default .md -> CHARTER_MD (nishi-silicon charters)
282 return NX_ART_KIND_CHARTER_MD
283 }
284 }
285 return NX_ART_KIND_OTHER
286}
287
288// ===== Top-level: walk one artifact + populate store =================================================
289
290func nx_pipeline_walker_walk_one(store: *NxArtifactStore,
291 path_z: *u8, path_n: i64) -> i64 {
292 if store.valid != 1 { return 0 - NX_PWALK_BAD_INPUT }
293 if (path_z as i64) == 0 { return 0 - NX_PWALK_BAD_INPUT }
294 if path_n < 1 { return 0 - NX_PWALK_BAD_INPUT }
295 if path_n > 512 { return 0 - NX_PWALK_BAD_INPUT }
296
297 // Read file
298 let lenbox: *u8 = sys_mmap(8)
299 let lp: *i64 = lenbox as *i64
300 lp[0] = 0
301 let body: *u8 = sys_read_file(path_z, lp)
302 if (body as i64) == 0 { return 0 - NX_PWALK_READ_FAILED }
303 let body_n: i64 = lp[0]
304 if body_n < 1 { return 0 - NX_PWALK_READ_FAILED }
305 if body_n > NX_PWALK_MAX_BYTES_PER_FILE { return 0 - NX_PWALK_FILE_TOO_LARGE }
306
307 // Classify kind from path
308 let kind: i64 = nx_pwalk_classify_kind(path_z, path_n)
309
310 // Add to store (commit hash empty V2.0; V2.5 reads from git via nx_git_walk)
311 let rowid: i64 = nx_artifact_store_add(store, path_z, path_n, kind,
312 0 as *u8, 0,
313 nx_pwalk_count_lines(body, body_n))
314 if rowid < 0 { return rowid }
315
316 // Parse 6-field front-matter
317 let val_off: *i64 = (sys_mmap(8)) as *i64
318 let val_len: *i64 = (sys_mmap(8)) as *i64
319
320 var quad: i64 = NX_ART_QUAD_NONE
321 val_off[0] = 0; val_len[0] = 0
322 if nx_pwalk_find_field(body, body_n, "Quadrant" as *u8, 8, val_off, val_len) == 1 {
323 quad = nx_pwalk_classify_quadrant(body, val_off[0], val_len[0])
324 }
325
326 var topic: i64 = NX_ART_DITA_NONE
327 val_off[0] = 0; val_len[0] = 0
328 if nx_pwalk_find_field(body, body_n, "Topic Type" as *u8, 10, val_off, val_len) == 1 {
329 topic = nx_pwalk_classify_topic_type(body, val_off[0], val_len[0])
330 }
331
332 var st: i64 = NX_ART_STATUS_NONE
333 val_off[0] = 0; val_len[0] = 0
334 if nx_pwalk_find_field(body, body_n, "Status" as *u8, 6, val_off, val_len) == 1 {
335 st = nx_pwalk_classify_status(body, val_off[0], val_len[0])
336 }
337
338 var trust: i64 = NX_ART_TRUST_NONE
339 val_off[0] = 0; val_len[0] = 0
340 if nx_pwalk_find_field(body, body_n, "Trust State" as *u8, 11, val_off, val_len) == 1 {
341 trust = nx_pwalk_classify_trust(body, val_off[0], val_len[0])
342 }
343
344 var comp: i64 = NX_ART_COMP_NONE
345 val_off[0] = 0; val_len[0] = 0
346 if nx_pwalk_find_field(body, body_n, "Competitive State" as *u8, 17, val_off, val_len) == 1 {
347 comp = nx_pwalk_classify_competitive(body, val_off[0], val_len[0])
348 }
349
350 let rc_tax: i64 = nx_artifact_store_set_taxonomy(store, rowid,
351 quad, topic, st, trust, comp)
352 if rc_tax != NX_ART_OK { return rc_tax }
353
354 // Composes count (signal for STAGE_MEANINGFUL)
355 let composes: i64 = nx_pwalk_count_composes(body, body_n)
356
357 // V2.0 P-6 + P-7: per-kind deep extraction (composes hub primitives).
358 // For .nx kinds: import_count + export_count via nx_doc_extract_nx_stats
359 // For .md kinds: heading_count -> import slot; code_block_count -> export slot
360 // (semantic re-use of i64 slots; sealed-enum kind makes interpretation safe)
361 var imports: i64 = 0
362 var exports: i64 = 0
363 if kind == NX_ART_KIND_RUNTIME_NX {
364 let imp_p: *i64 = (sys_mmap(8)) as *i64
365 let exp_p: *i64 = (sys_mmap(8)) as *i64
366 imp_p[0] = 0; exp_p[0] = 0
367 let rc_x: i64 = nx_doc_extract_nx_stats(body, body_n, imp_p, exp_p)
368 if rc_x == NX_DXNX_OK { imports = imp_p[0]; exports = exp_p[0] }
369 }
370 if kind == NX_ART_KIND_TEST_NX {
371 let imp_p: *i64 = (sys_mmap(8)) as *i64
372 let exp_p: *i64 = (sys_mmap(8)) as *i64
373 imp_p[0] = 0; exp_p[0] = 0
374 let rc_x: i64 = nx_doc_extract_nx_stats(body, body_n, imp_p, exp_p)
375 if rc_x == NX_DXNX_OK { imports = imp_p[0]; exports = exp_p[0] }
376 }
377 if kind == NX_ART_KIND_SILICON_ARC {
378 let imp_p: *i64 = (sys_mmap(8)) as *i64
379 let exp_p: *i64 = (sys_mmap(8)) as *i64
380 imp_p[0] = 0; exp_p[0] = 0
381 let rc_x: i64 = nx_doc_extract_nx_stats(body, body_n, imp_p, exp_p)
382 if rc_x == NX_DXNX_OK { imports = imp_p[0]; exports = exp_p[0] }
383 }
384 if kind == NX_ART_KIND_CHARTER_MD {
385 let h_p: *i64 = (sys_mmap(8)) as *i64
386 let c_p: *i64 = (sys_mmap(8)) as *i64
387 h_p[0] = 0; c_p[0] = 0
388 let rc_x: i64 = nx_doc_extract_md_stats(body, body_n, h_p, c_p)
389 if rc_x == NX_DXMD_OK { imports = h_p[0]; exports = c_p[0] }
390 }
391 if kind == NX_ART_KIND_RFC_MD {
392 let h_p: *i64 = (sys_mmap(8)) as *i64
393 let c_p: *i64 = (sys_mmap(8)) as *i64
394 h_p[0] = 0; c_p[0] = 0
395 let rc_x: i64 = nx_doc_extract_md_stats(body, body_n, h_p, c_p)
396 if rc_x == NX_DXMD_OK { imports = h_p[0]; exports = c_p[0] }
397 }
398 if kind == NX_ART_KIND_DASHBOARD_MD {
399 let h_p: *i64 = (sys_mmap(8)) as *i64
400 let c_p: *i64 = (sys_mmap(8)) as *i64
401 h_p[0] = 0; c_p[0] = 0
402 let rc_x: i64 = nx_doc_extract_md_stats(body, body_n, h_p, c_p)
403 if rc_x == NX_DXMD_OK { imports = h_p[0]; exports = c_p[0] }
404 }
405 if kind == NX_ART_KIND_MEMORY_MD {
406 let h_p: *i64 = (sys_mmap(8)) as *i64
407 let c_p: *i64 = (sys_mmap(8)) as *i64
408 h_p[0] = 0; c_p[0] = 0
409 let rc_x: i64 = nx_doc_extract_md_stats(body, body_n, h_p, c_p)
410 if rc_x == NX_DXMD_OK { imports = h_p[0]; exports = c_p[0] }
411 }
412
413 let rc_stats: i64 = nx_artifact_store_set_stats(store, rowid, imports, exports, composes)
414 if rc_stats != NX_ART_OK { return rc_stats }
415
416 // Derive pipeline stage from taxonomy + stats
417 let stage: i64 = nx_artifact_store_derive_stage(store, rowid)
418 if stage < 0 { return stage }
419
420 return rowid
421}
422
423// ===== Top-level: walk a list of paths =================================================
424//
425// Caller supplies an array of NUL-terminated path pointers + count.
426// Returns NX_PWALK_OK on success; first error verdict on failure.
427
428func nx_pipeline_walker_walk_list(store: *NxArtifactStore,
429 paths: *i64, paths_count: i64) -> i64 {
430 if store.valid != 1 { return 0 - NX_PWALK_BAD_INPUT }
431 if (paths as i64) == 0 { return 0 - NX_PWALK_BAD_INPUT }
432 if paths_count < 1 { return NX_PWALK_OK } // empty list is valid
433
434 var i: i64 = 0
435 while i < paths_count {
436 let path_ptr: *u8 = paths[i] as *u8
437 if (path_ptr as i64) == 0 { i = i + 1 }
438 if (path_ptr as i64) != 0 {
439 // Compute path length (NUL-terminated)
440 var n: i64 = 0
441 while n < 512 {
442 if path_ptr[n] == (0 as u8) { n = 512 + 1 }
443 if n <= 512 { if n < 512 { n = n + 1 } }
444 }
445 let real_n: i64 = if n > 512 then n - 513 else n
446 // Walk one; ignore per-file errors (continue walking; surface
447 // each error via store record's missing fields).
448 let rc: i64 = nx_pipeline_walker_walk_one(store, path_ptr, real_n)
449 if rc < 0 {
450 // Per Cardinal 14 (graceful degradation): record absence + continue
451 }
452 i = i + 1
453 }
454 }
455 return NX_PWALK_OK
456}