code wiki / wiki / nx_artifact_store.nx

nx_artifact_store.nx source

↩ module page · 434 lines · 18401 B

1// nx_artifact_store.nx -- pipeline-aware artifact metadata store. 2// 3// Extension of NxWikiDocStore (V1 SHIPPED at 08e67598) with pipeline 4// stage + V5 living-docs taxonomy fields (per V2_0_PIPELINE_BOOTSTRAP_ARC_PLAN §2.0). 5// 6// COMPOSES (zero new tokenization / parse / hash code): 7// wiki/nx_wiki_index_builder (NxWikiDocStore base) 8// nx_search_inverted (nx_inv_hash_bytes_lower for path-hash) 9// 10// COMPOSED BY: 11// wiki/nx_pipeline_walker.nx (P-1; populates this store) 12// wiki/nx_pipeline_route.nx (P-3; renders this store as /wiki/pipeline) 13// 14// Per operator cardinal 2026-05-27 "from zero everything nishi": pure 15// NishiLang; composes existing audit primitives (nx_doc_xref D22 + 16// nx_doc_census D1); zero bash + sed. 17// 18// V2.0 SCOPE: 19// - Parallel-pool storage per artifact (path / kind / pipeline_stage / 20// quadrant / topic_type / status / trust_state / competitive_state / 21// last_commit_hash / line_count) 22// - Insert + lookup by path-hash (FNV-1a 64 via existing primitive) 23// - Iterate by stage + by kind (filtered scans) 24// 25// Status: V2.0. 2026-05-27. 26 27import "nx_syscalls.nx" 28import "nx_search_inverted.nx" 29 30// ===== Sealed verdict surface (codes 2900-2919; V2.0 reserved) ================================================= 31const NX_ART_OK: i64 = 0 32const NX_ART_BAD_INPUT: i64 = 2900 33const NX_ART_STORE_FULL: i64 = 2901 34const NX_ART_POOL_OVERFLOW: i64 = 2902 35const NX_ART_NOT_FOUND: i64 = 2903 36const NX_ART_DUPLICATE_PATH: i64 = 2904 37const NX_ART_BAD_STAGE: i64 = 2905 38 39// ===== Sealed pipeline stage enum (per NISHI_INTELLIGENT_WIKI_CHARTER §1) ================================================= 40const NX_ART_STAGE_UNSTRUCTURED: i64 = 0 41const NX_ART_STAGE_STRUCTURED: i64 = 1 42const NX_ART_STAGE_MEANINGFUL: i64 = 2 43const NX_ART_STAGE_ACTIONABLE: i64 = 3 44const NX_ART_STAGE_REPEATABLE: i64 = 4 45const NX_ART_STAGE_N: i64 = 5 46 47// ===== Sealed kind enum (per V2.0 PLAN §1 inventory) ================================================= 48const NX_ART_KIND_UNKNOWN: i64 = 0 49const NX_ART_KIND_RUNTIME_NX: i64 = 1 // nxc2/runtime/*.nx 50const NX_ART_KIND_CHARTER_MD: i64 = 2 // nishi-silicon/*.md 51const NX_ART_KIND_BENCH_SH: i64 = 3 // nxc2/bench/*.sh 52const NX_ART_KIND_RFC_MD: i64 = 4 // nishi-silicon/RFC*.md or *_DOCTRINE_*.md 53const NX_ART_KIND_MEMORY_MD: i64 = 5 // memory/*.md (operator-private) 54const NX_ART_KIND_DASHBOARD_MD: i64 = 6 // nxc2/docs/dashboards/*.md 55const NX_ART_KIND_SILICON_ARC: i64 = 7 // nishi-silicon/hdl/*.md or *.nx 56const NX_ART_KIND_TEST_NX: i64 = 8 // *_test.nx 57const NX_ART_KIND_OTHER: i64 = 9 58const NX_ART_KIND_N: i64 = 10 59 60// ===== Sealed Diátaxis quadrant (per nxc2 V5 living-docs taxonomy) ================================================= 61const NX_ART_QUAD_NONE: i64 = 0 // missing front-matter 62const NX_ART_QUAD_TUTORIAL: i64 = 1 63const NX_ART_QUAD_HOWTO: i64 = 2 64const NX_ART_QUAD_REFERENCE: i64 = 3 65const NX_ART_QUAD_EXPLANATION: i64 = 4 66const NX_ART_QUAD_N: i64 = 5 67 68// ===== Sealed DITA topic type ================================================= 69const NX_ART_DITA_NONE: i64 = 0 70const NX_ART_DITA_TASK: i64 = 1 71const NX_ART_DITA_CONCEPT: i64 = 2 72const NX_ART_DITA_REFERENCE: i64 = 3 73const NX_ART_DITA_GLOSSARY: i64 = 4 74const NX_ART_DITA_N: i64 = 5 75 76// ===== Sealed status (substrate-defined) ================================================= 77const NX_ART_STATUS_NONE: i64 = 0 78const NX_ART_STATUS_CANONICAL: i64 = 1 79const NX_ART_STATUS_WIP: i64 = 2 80const NX_ART_STATUS_DEPRECATED: i64 = 3 81const NX_ART_STATUS_N: i64 = 4 82 83// ===== Sealed Trust State (substrate-defined V5 provenance tier) ================================================= 84const NX_ART_TRUST_NONE: i64 = 0 85const NX_ART_TRUST_WRITTEN_UNTESTED: i64 = 1 86const NX_ART_TRUST_WEBSEARCH_VERIFIED: i64 = 2 87const NX_ART_TRUST_EXPERT_VERIFIED: i64 = 3 88const NX_ART_TRUST_PERSONALLY_MEASURED: i64 = 4 89const NX_ART_TRUST_N: i64 = 5 90 91// ===== Sealed Competitive State (substrate-defined V5 benchmark spec) ================================================= 92const NX_ART_COMP_NONE: i64 = 0 93const NX_ART_COMP_UNCLASSIFIED: i64 = 1 94const NX_ART_COMP_UNDER: i64 = 2 95const NX_ART_COMP_MATCHES: i64 = 3 96const NX_ART_COMP_BEATS: i64 = 4 97const NX_ART_COMP_N: i64 = 5 98 99// ===== Named sizing constants (M7) ================================================= 100const NX_ART_DEFAULT_CAP: i64 = 1000 // V2.0 bounded; covers ~230 known artifacts + headroom 101const NX_ART_HARD_CAP: i64 = 10000 102const NX_ART_PATH_POOL_CAP: i64 = 524288 // 512 KB packed paths 103const NX_ART_HASH_POOL_CAP: i64 = 524288 // 512 KB packed commit hashes 104const NX_ART_MAX_PATH_LEN: i64 = 512 105const NX_ART_LOOP_BUDGET_CAP: i64 = 10000000 106 107// ===== NxArtifactStore: parallel pools ================================================= 108 109struct NxArtifactStore { 110 // Path identification 111 paths_pool: *u8 // packed UTF-8 paths 112 paths_pool_cap: i64 113 paths_pool_used: i64 114 paths_offs: *i64 // per-artifact offset into paths_pool 115 paths_lens: *i64 // per-artifact path length 116 path_hashes: *i64 // FNV-1a 64 of path (for O(1) lookup) 117 118 // Last-commit metadata 119 hashes_pool: *u8 // packed 40-char SHA-1 hashes 120 hashes_pool_cap: i64 121 hashes_pool_used: i64 122 hashes_offs: *i64 123 hashes_lens: *i64 124 125 // Per-artifact classification (parallel arrays; rowid-indexed) 126 kind: *i64 // NX_ART_KIND_* 127 pipeline_stage: *i64 // NX_ART_STAGE_* 128 quadrant: *i64 // NX_ART_QUAD_* 129 topic_type: *i64 // NX_ART_DITA_* 130 status: *i64 // NX_ART_STATUS_* 131 trust_state: *i64 // NX_ART_TRUST_* 132 competitive_state: *i64 // NX_ART_COMP_* 133 134 // Per-artifact stats 135 line_count: *i64 136 import_count: *i64 // for .nx kinds 137 export_count: *i64 // # of public funcs for .nx kinds 138 composes_count: *i64 // # of [[X]] refs in Composes section 139 140 // Bookkeeping 141 artifact_count: i64 142 artifact_cap: i64 143 valid: i64 144} 145 146// ===== Sealed init ================================================= 147 148func nx_artifact_store_init(s: *NxArtifactStore, cap: i64) -> i64 { 149 if (s as i64) == 0 { return 0 - NX_ART_BAD_INPUT } 150 if cap < 1 { return 0 - NX_ART_BAD_INPUT } 151 if cap > NX_ART_HARD_CAP { return 0 - NX_ART_STORE_FULL } 152 153 // Pools 154 s.paths_pool = sys_mmap(NX_ART_PATH_POOL_CAP) 155 s.paths_pool_cap = NX_ART_PATH_POOL_CAP 156 s.paths_pool_used = 0 157 s.paths_offs = (sys_mmap(cap * 8)) as *i64 158 s.paths_lens = (sys_mmap(cap * 8)) as *i64 159 s.path_hashes = (sys_mmap(cap * 8)) as *i64 160 161 s.hashes_pool = sys_mmap(NX_ART_HASH_POOL_CAP) 162 s.hashes_pool_cap = NX_ART_HASH_POOL_CAP 163 s.hashes_pool_used = 0 164 s.hashes_offs = (sys_mmap(cap * 8)) as *i64 165 s.hashes_lens = (sys_mmap(cap * 8)) as *i64 166 167 s.kind = (sys_mmap(cap * 8)) as *i64 168 s.pipeline_stage = (sys_mmap(cap * 8)) as *i64 169 s.quadrant = (sys_mmap(cap * 8)) as *i64 170 s.topic_type = (sys_mmap(cap * 8)) as *i64 171 s.status = (sys_mmap(cap * 8)) as *i64 172 s.trust_state = (sys_mmap(cap * 8)) as *i64 173 s.competitive_state = (sys_mmap(cap * 8)) as *i64 174 175 s.line_count = (sys_mmap(cap * 8)) as *i64 176 s.import_count = (sys_mmap(cap * 8)) as *i64 177 s.export_count = (sys_mmap(cap * 8)) as *i64 178 s.composes_count = (sys_mmap(cap * 8)) as *i64 179 180 s.artifact_count = 0 181 s.artifact_cap = cap 182 s.valid = 1 183 return NX_ART_OK 184} 185 186// ===== Add an artifact ================================================= 187 188func nx_artifact_store_add(s: *NxArtifactStore, 189 path: *u8, path_n: i64, 190 kind: i64, 191 last_commit_hash: *u8, hash_n: i64, 192 line_count: i64) -> i64 { 193 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 194 if s.artifact_count >= s.artifact_cap { return 0 - NX_ART_STORE_FULL } 195 if path_n < 1 { return 0 - NX_ART_BAD_INPUT } 196 if path_n > NX_ART_MAX_PATH_LEN { return 0 - NX_ART_BAD_INPUT } 197 if kind < 0 { return 0 - NX_ART_BAD_INPUT } 198 if kind >= NX_ART_KIND_N { return 0 - NX_ART_BAD_INPUT } 199 if hash_n < 0 { return 0 - NX_ART_BAD_INPUT } 200 if hash_n > 40 { return 0 - NX_ART_BAD_INPUT } 201 if line_count < 0 { return 0 - NX_ART_BAD_INPUT } 202 203 let rowid: i64 = s.artifact_count 204 205 // Path 206 if s.paths_pool_used + path_n > s.paths_pool_cap { return 0 - NX_ART_POOL_OVERFLOW } 207 let p_off: i64 = s.paths_pool_used 208 var i: i64 = 0 209 while i < path_n { s.paths_pool[p_off + i] = path[i]; i = i + 1 } 210 s.paths_pool_used = s.paths_pool_used + path_n 211 s.paths_offs[rowid] = p_off 212 s.paths_lens[rowid] = path_n 213 s.path_hashes[rowid] = nx_inv_hash_bytes_lower(path, path_n) 214 215 // Last-commit hash 216 if hash_n > 0 { 217 if s.hashes_pool_used + hash_n > s.hashes_pool_cap { return 0 - NX_ART_POOL_OVERFLOW } 218 let h_off: i64 = s.hashes_pool_used 219 i = 0 220 while i < hash_n { s.hashes_pool[h_off + i] = last_commit_hash[i]; i = i + 1 } 221 s.hashes_pool_used = s.hashes_pool_used + hash_n 222 s.hashes_offs[rowid] = h_off 223 s.hashes_lens[rowid] = hash_n 224 } 225 if hash_n == 0 { 226 s.hashes_offs[rowid] = 0 227 s.hashes_lens[rowid] = 0 228 } 229 230 // Classification: default to UNSTRUCTURED + UNCLASSIFIED; walker 231 // fills these in via nx_artifact_store_set_taxonomy after parse. 232 s.kind[rowid] = kind 233 s.pipeline_stage[rowid] = NX_ART_STAGE_UNSTRUCTURED 234 s.quadrant[rowid] = NX_ART_QUAD_NONE 235 s.topic_type[rowid] = NX_ART_DITA_NONE 236 s.status[rowid] = NX_ART_STATUS_NONE 237 s.trust_state[rowid] = NX_ART_TRUST_NONE 238 s.competitive_state[rowid] = NX_ART_COMP_NONE 239 240 s.line_count[rowid] = line_count 241 s.import_count[rowid] = 0 242 s.export_count[rowid] = 0 243 s.composes_count[rowid] = 0 244 245 s.artifact_count = s.artifact_count + 1 246 return rowid 247} 248 249// ===== Set taxonomy fields (called by walker after front-matter parse) ================================================= 250 251func nx_artifact_store_set_taxonomy(s: *NxArtifactStore, rowid: i64, 252 quadrant: i64, topic_type: i64, 253 status: i64, 254 trust_state: i64, 255 competitive_state: i64) -> i64 { 256 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 257 if rowid < 0 { return 0 - NX_ART_BAD_INPUT } 258 if rowid >= s.artifact_count { return 0 - NX_ART_NOT_FOUND } 259 if quadrant < 0 { return 0 - NX_ART_BAD_INPUT } 260 if quadrant >= NX_ART_QUAD_N { return 0 - NX_ART_BAD_INPUT } 261 if topic_type < 0 { return 0 - NX_ART_BAD_INPUT } 262 if topic_type >= NX_ART_DITA_N { return 0 - NX_ART_BAD_INPUT } 263 if status < 0 { return 0 - NX_ART_BAD_INPUT } 264 if status >= NX_ART_STATUS_N { return 0 - NX_ART_BAD_INPUT } 265 if trust_state < 0 { return 0 - NX_ART_BAD_INPUT } 266 if trust_state >= NX_ART_TRUST_N { return 0 - NX_ART_BAD_INPUT } 267 if competitive_state < 0 { return 0 - NX_ART_BAD_INPUT } 268 if competitive_state >= NX_ART_COMP_N { return 0 - NX_ART_BAD_INPUT } 269 270 s.quadrant[rowid] = quadrant 271 s.topic_type[rowid] = topic_type 272 s.status[rowid] = status 273 s.trust_state[rowid] = trust_state 274 s.competitive_state[rowid] = competitive_state 275 return NX_ART_OK 276} 277 278// ===== Set stats (called by walker after content analysis) ================================================= 279 280func nx_artifact_store_set_stats(s: *NxArtifactStore, rowid: i64, 281 import_count: i64, export_count: i64, 282 composes_count: i64) -> i64 { 283 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 284 if rowid < 0 { return 0 - NX_ART_BAD_INPUT } 285 if rowid >= s.artifact_count { return 0 - NX_ART_NOT_FOUND } 286 if import_count < 0 { return 0 - NX_ART_BAD_INPUT } 287 if export_count < 0 { return 0 - NX_ART_BAD_INPUT } 288 if composes_count < 0 { return 0 - NX_ART_BAD_INPUT } 289 290 s.import_count[rowid] = import_count 291 s.export_count[rowid] = export_count 292 s.composes_count[rowid] = composes_count 293 return NX_ART_OK 294} 295 296// ===== Derive pipeline stage from taxonomy + stats (per V2.0 PLAN §2.0 mapping) ================================================= 297// 298// Sealed rules (operator-existing taxonomy → derived stage): 299// STAGE_REPEATABLE iff trust=PERSONALLY_MEASURED + comp∈{MATCHES,BEATS} 300// STAGE_ACTIONABLE iff trust>WRITTEN_UNTESTED + comp!=NONE 301// STAGE_MEANINGFUL iff status!=NONE + composes_count>0 302// STAGE_STRUCTURED iff quadrant!=NONE + topic_type!=NONE + status!=NONE 303// STAGE_UNSTRUCTURED otherwise 304 305func nx_artifact_store_derive_stage(s: *NxArtifactStore, rowid: i64) -> i64 { 306 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 307 if rowid < 0 { return 0 - NX_ART_BAD_INPUT } 308 if rowid >= s.artifact_count { return 0 - NX_ART_NOT_FOUND } 309 310 let q: i64 = s.quadrant[rowid] 311 let tt: i64 = s.topic_type[rowid] 312 let st: i64 = s.status[rowid] 313 let tr: i64 = s.trust_state[rowid] 314 let co: i64 = s.competitive_state[rowid] 315 let nc: i64 = s.composes_count[rowid] 316 317 var stage: i64 = NX_ART_STAGE_UNSTRUCTURED 318 319 // STRUCTURED: all 3 of (quadrant, topic_type, status) present 320 if q != NX_ART_QUAD_NONE { 321 if tt != NX_ART_DITA_NONE { 322 if st != NX_ART_STATUS_NONE { stage = NX_ART_STAGE_STRUCTURED } 323 } 324 } 325 326 // MEANINGFUL: + composes count > 0 (composes nx_doc_xref signal) 327 if stage == NX_ART_STAGE_STRUCTURED { 328 if nc > 0 { stage = NX_ART_STAGE_MEANINGFUL } 329 } 330 331 // ACTIONABLE: + trust state set (NOT WRITTEN_UNTESTED) + comp set 332 if stage == NX_ART_STAGE_MEANINGFUL { 333 if tr > NX_ART_TRUST_WRITTEN_UNTESTED { 334 if co != NX_ART_COMP_NONE { stage = NX_ART_STAGE_ACTIONABLE } 335 } 336 } 337 338 // REPEATABLE: + trust=PERSONALLY_MEASURED + comp∈{MATCHES, BEATS} 339 if stage == NX_ART_STAGE_ACTIONABLE { 340 if tr == NX_ART_TRUST_PERSONALLY_MEASURED { 341 if co >= NX_ART_COMP_MATCHES { stage = NX_ART_STAGE_REPEATABLE } 342 } 343 } 344 345 // Status==DEPRECATED freezes stage (no auto-advance; operator action only) 346 if st == NX_ART_STATUS_DEPRECATED { stage = s.pipeline_stage[rowid] } 347 348 s.pipeline_stage[rowid] = stage 349 return stage 350} 351 352// ===== Accessors ================================================= 353 354func nx_artifact_store_count(s: *NxArtifactStore) -> i64 { 355 if s.valid != 1 { return 0 } 356 return s.artifact_count 357} 358 359func nx_artifact_store_count_by_stage(s: *NxArtifactStore, stage: i64) -> i64 { 360 if s.valid != 1 { return 0 } 361 if stage < 0 { return 0 } 362 if stage >= NX_ART_STAGE_N { return 0 } 363 var i: i64 = 0 364 var n: i64 = 0 365 while i < s.artifact_count { 366 if s.pipeline_stage[i] == stage { n = n + 1 } 367 i = i + 1 368 } 369 return n 370} 371 372func nx_artifact_store_path_at(s: *NxArtifactStore, rowid: i64, 373 out_ptr: *i64, out_n: *i64) -> i64 { 374 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 375 if rowid < 0 { return 0 - NX_ART_BAD_INPUT } 376 if rowid >= s.artifact_count { return 0 - NX_ART_NOT_FOUND } 377 if (out_ptr as i64) == 0 { return 0 - NX_ART_BAD_INPUT } 378 if (out_n as i64) == 0 { return 0 - NX_ART_BAD_INPUT } 379 out_ptr[0] = (s.paths_pool as i64) + s.paths_offs[rowid] 380 out_n[0] = s.paths_lens[rowid] 381 return NX_ART_OK 382} 383 384func nx_artifact_store_stage_at(s: *NxArtifactStore, rowid: i64) -> i64 { 385 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 386 if rowid < 0 { return 0 - NX_ART_BAD_INPUT } 387 if rowid >= s.artifact_count { return 0 - NX_ART_NOT_FOUND } 388 return s.pipeline_stage[rowid] 389} 390 391func nx_artifact_store_kind_at(s: *NxArtifactStore, rowid: i64) -> i64 { 392 if s.valid != 1 { return 0 - NX_ART_BAD_INPUT } 393 if rowid < 0 { return 0 - NX_ART_BAD_INPUT } 394 if rowid >= s.artifact_count { return 0 - NX_ART_NOT_FOUND } 395 return s.kind[rowid] 396} 397 398// Look up by path-hash (O(N) linear scan; V2.0 acceptable for ~1000 399// artifacts; V3 swaps for hash-keyed lookup). 400func nx_artifact_store_find_by_path(s: *NxArtifactStore, 401 path: *u8, path_n: i64) -> i64 { 402 if s.valid != 1 { return 0 - NX_ART_NOT_FOUND } 403 if path_n < 1 { return 0 - NX_ART_BAD_INPUT } 404 let h: i64 = nx_inv_hash_bytes_lower(path, path_n) 405 var i: i64 = 0 406 while i < s.artifact_count { 407 if s.path_hashes[i] == h { return i } 408 i = i + 1 409 } 410 return 0 - NX_ART_NOT_FOUND 411} 412 413// Sealed-name accessors for stage/kind/quadrant/etc (for renderer) 414func nx_art_stage_name(s: i64) -> *u8 { 415 if s == NX_ART_STAGE_UNSTRUCTURED { return "UNSTRUCTURED" as *u8 } 416 if s == NX_ART_STAGE_STRUCTURED { return "STRUCTURED" as *u8 } 417 if s == NX_ART_STAGE_MEANINGFUL { return "MEANINGFUL" as *u8 } 418 if s == NX_ART_STAGE_ACTIONABLE { return "ACTIONABLE" as *u8 } 419 if s == NX_ART_STAGE_REPEATABLE { return "REPEATABLE" as *u8 } 420 return "UNKNOWN" as *u8 421} 422 423func nx_art_kind_name(k: i64) -> *u8 { 424 if k == NX_ART_KIND_RUNTIME_NX { return "RUNTIME_NX" as *u8 } 425 if k == NX_ART_KIND_CHARTER_MD { return "CHARTER_MD" as *u8 } 426 if k == NX_ART_KIND_BENCH_SH { return "BENCH_SH" as *u8 } 427 if k == NX_ART_KIND_RFC_MD { return "RFC_MD" as *u8 } 428 if k == NX_ART_KIND_MEMORY_MD { return "MEMORY_MD" as *u8 } 429 if k == NX_ART_KIND_DASHBOARD_MD{ return "DASHBOARD_MD"as *u8 } 430 if k == NX_ART_KIND_SILICON_ARC { return "SILICON_ARC" as *u8 } 431 if k == NX_ART_KIND_TEST_NX { return "TEST_NX" as *u8 } 432 if k == NX_ART_KIND_OTHER { return "OTHER" as *u8 } 433 return "UNKNOWN" as *u8 434}