nx_asset_search_gate.nx source
↩ module page · 137 lines · 7759 B
1// nx_asset_search_gate.nx -- KAT + TEETH for nx_asset_search (faceted findability over the catalog).
2//
3// Ingests 4 known records into a fresh catalog then proves the facet filters return EXACTLY the right
4// sets (and the right CIDs):
5// A image / professional / tags="gallery,generated"
6// B image / private / tags="gallery,private"
7// C doc / professional / tags="wiki,doctrine"
8// D video / professional / tags="clip"
9// (a) by type=image -> 2 (b) by type=doc -> 1 (c) by type=video -> 1
10// (d) by classification=private -> 1 (e) by classification=professional -> 3
11// (f) by tag=gallery -> 2 (g) by tag=doctrine -> 1
12// (h) membership: the type=doc result actually contains C's CID
13// TEETH (must be empty): (i) type=audio -> 0 (j) tag=nonexistent -> 0
14//
15// Verdict appended to knowledge/status/asset_search_gate.log (additive law #13).
16// expect_exit: 0 license_tier: ORIGINAL
17import "nx_syscalls.nx"
18import "nx_canon_cid.nx"
19import "nx_asset_record.nx"
20import "nx_asset_catalog.nx"
21import "nx_asset_search.nx"
22import "nx_gate_verdict.nx"
23
24func g_puts(logfd: i64, s: *u8) -> i64 {
25 var n: i64 = 0
26 while s[n] != (0 as u8) { n = n + 1 }
27 sys_write(1, s, n)
28 if logfd > 0 { sys_write(logfd, s, n) }
29 return 0
30}
31func g_putn(logfd: i64, v: i64) -> i64 {
32 let bb: *u8 = sys_mmap(28)
33 var m: i64 = v
34 if m < 0 { g_puts(logfd, "-\x00" as *u8); m = 0 - m }
35 let t: *u8 = sys_mmap(28)
36 var k: i64 = 0
37 if m == 0 { t[0] = 48 as u8; k = 1 }
38 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
39 var i: i64 = 0
40 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
41 sys_write(1, bb, k)
42 if logfd > 0 { sys_write(logfd, bb, k) }
43 return 0
44}
45func E() -> *u8 { return "\x00" as *u8 }
46func sset(a: *i64, i: i64, s: *u8) -> i64 { a[i] = s as i64; return 0 }
47
48// build an asset record: type / classification / tags / id (others empty). returns byte length.
49func mk_asset(typ: *u8, cls: *u8, tags: *u8, id: *u8, out: *u8) -> i64 {
50 let core: *i64 = sys_mmap(8 * 8) as *i64
51 sset(core, 0, typ); sset(core, 1, "Asset\x00" as *u8); sset(core, 2, E())
52 sset(core, 3, "2026-06-20\x00" as *u8); sset(core, 4, id); sset(core, 5, E()); sset(core, 6, E())
53 let pz: *i64 = sys_mmap(8 * 8) as *i64
54 sset(pz, 0, E()); sset(pz, 1, E()); sset(pz, 2, E()); sset(pz, 3, E()); sset(pz, 4, E()); sset(pz, 5, E())
55 let mz: *i64 = sys_mmap(8 * 8) as *i64
56 sset(mz, 0, E()); sset(mz, 1, E()); sset(mz, 2, E()); sset(mz, 3, E())
57 let oz: *i64 = sys_mmap(8 * 8) as *i64
58 sset(oz, 0, tags); sset(oz, 1, E()); sset(oz, 2, E()); sset(oz, 3, "1\x00" as *u8); sset(oz, 4, cls); sset(oz, 5, E())
59 let keys: *i64 = sys_mmap(8 * 48) as *i64
60 let vals: *i64 = sys_mmap(8 * 48) as *i64
61 let n: i64 = ar_fields(core, pz, mz, oz, keys, vals)
62 return ar_encode(keys, vals, n, out)
63}
64
65func gt_prefix(prefix: *u8, base: *u8) -> i64 {
66 var po: i64 = 0
67 while base[po] != (0 as u8) { prefix[po] = base[po]; po = po + 1 }
68 var m: i64 = sys_now_ms()
69 let ds: *u8 = sys_mmap(28)
70 var k: i64 = 0
71 if m == 0 { ds[0] = 48 as u8; k = 1 }
72 while m > 0 { ds[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
73 var j: i64 = 0
74 while j < k { prefix[po] = ds[k - 1 - j]; po = po + 1; j = j + 1 }
75 prefix[po] = 45 as u8; po = po + 1
76 prefix[po] = 0 as u8
77 return po
78}
79
80func expect_count(logfd: i64, label: *u8, got: i64, want: i64) -> i64 {
81 g_puts(logfd, label); g_puts(logfd, " got=\x00" as *u8); g_putn(logfd, got); g_puts(logfd, " want=\x00" as *u8); g_putn(logfd, want); g_puts(logfd, ": \x00" as *u8)
82 if got == want { g_puts(logfd, "PASS\n\x00" as *u8); return 1 }
83 g_puts(logfd, "FAIL\n\x00" as *u8); return 0
84}
85
86func main() -> i64 {
87 let logfd: i64 = sys_openat_append("knowledge/status/asset_search_gate.log\x00" as *u8, 0x1a4)
88 g_puts(logfd, "=== ASSET-SEARCH-GATE (faceted findability over the catalog) ===\n\x00" as *u8)
89
90 let prefix: *u8 = sys_mmap(256); gt_prefix(prefix, "/tmp/assrch-\x00" as *u8)
91 let rA: *u8 = sys_mmap(8192); let nA: i64 = mk_asset("image\x00" as *u8, "professional\x00" as *u8, "gallery,generated\x00" as *u8, "s-a\x00" as *u8, rA)
92 let rB: *u8 = sys_mmap(8192); let nB: i64 = mk_asset("image\x00" as *u8, "private\x00" as *u8, "gallery,private\x00" as *u8, "s-b\x00" as *u8, rB)
93 let rC: *u8 = sys_mmap(8192); let nC: i64 = mk_asset("doc\x00" as *u8, "professional\x00" as *u8, "wiki,doctrine\x00" as *u8, "s-c\x00" as *u8, rC)
94 let rD: *u8 = sys_mmap(8192); let nD: i64 = mk_asset("video\x00" as *u8, "professional\x00" as *u8, "clip\x00" as *u8, "s-d\x00" as *u8, rD)
95
96 let st: *i64 = sys_mmap(16) as *i64
97 let cidC: *u8 = sys_mmap(128)
98 let junk: *u8 = sys_mmap(128)
99 cat_ingest_cid(prefix, rA, nA, junk, st)
100 cat_ingest_cid(prefix, rB, nB, junk, st)
101 cat_ingest_cid(prefix, rC, nC, cidC, st)
102 cat_ingest_cid(prefix, rD, nD, junk, st)
103 g_puts(logfd, " ingested 4 records, catalog count=\x00" as *u8); g_putn(logfd, cat_count(prefix)); g_puts(logfd, "\n\x00" as *u8)
104
105 let out: *i64 = sys_mmap(8 * 64) as *i64
106 var pass: i64 = 0
107 var total: i64 = 0
108
109 total = total + 1; pass = pass + expect_count(logfd, " (a) type=image\x00" as *u8, as_by_field(prefix, "type\x00" as *u8, "image\x00" as *u8, out, 64), 2)
110 total = total + 1; pass = pass + expect_count(logfd, " (b) type=doc\x00" as *u8, as_by_field(prefix, "type\x00" as *u8, "doc\x00" as *u8, out, 64), 1)
111 total = total + 1; pass = pass + expect_count(logfd, " (c) type=video\x00" as *u8, as_by_field(prefix, "type\x00" as *u8, "video\x00" as *u8, out, 64), 1)
112 total = total + 1; pass = pass + expect_count(logfd, " (d) classification=private\x00" as *u8, as_by_field(prefix, "classification\x00" as *u8, "private\x00" as *u8, out, 64), 1)
113 total = total + 1; pass = pass + expect_count(logfd, " (e) classification=professional\x00" as *u8, as_by_field(prefix, "classification\x00" as *u8, "professional\x00" as *u8, out, 64), 3)
114 total = total + 1; pass = pass + expect_count(logfd, " (f) tag=gallery\x00" as *u8, as_by_tag(prefix, "gallery\x00" as *u8, out, 64), 2)
115 total = total + 1; pass = pass + expect_count(logfd, " (g) tag=doctrine\x00" as *u8, as_by_tag(prefix, "doctrine\x00" as *u8, out, 64), 1)
116
117 // (h) membership: the type=doc result actually contains C's CID
118 let ndoc: i64 = as_by_field(prefix, "type\x00" as *u8, "doc\x00" as *u8, out, 64)
119 var memok: i64 = 0
120 if cat_idx_has(out, ndoc, cidC) == 1 { memok = 1 }
121 total = total + 1; pass = pass + expect_count(logfd, " (h) doc result contains C's CID\x00" as *u8, memok, 1)
122
123 // TEETH: empty results for absent facets (no false matches)
124 total = total + 1; pass = pass + expect_count(logfd, " (i TEETH) type=audio (none)\x00" as *u8, as_by_field(prefix, "type\x00" as *u8, "audio\x00" as *u8, out, 64), 0)
125 total = total + 1; pass = pass + expect_count(logfd, " (j TEETH) tag=nonexistent (none)\x00" as *u8, as_by_tag(prefix, "nonexistent\x00" as *u8, out, 64), 0)
126
127 g_puts(logfd, "ASSET-SEARCH-GATE passed \x00" as *u8); g_putn(logfd, pass); g_puts(logfd, "/\x00" as *u8); g_putn(logfd, total)
128 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
129 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
130 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
131 let ctr__dry: *i64 = gv_ctr()
132 ctr__dry[0] = pass
133 ctr__dry[1] = total
134 let rc__dry: i64 = gv_verdict("ASSET-SEARCH-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
135 sys_exit(rc__dry)
136 return rc__dry
137}