nx_asset_record_gate.nx source
↩ module page · 332 lines · 19173 B
1// nx_asset_record_gate.nx -- KAT + TEETH for nx_asset_record (R0 of the universal org-tooling arc).
2//
3// Proves the unified content-addressed ASSET RECORD on real bytes through the real durable store:
4// (a) DETERMINISTIC IDENTITY same record bytes -> same CID; ONE changed field -> DIFFERENT CID
5// (b) ROUND-TRIP ar_encode -> ar_put -> ar_get_by_cid -> ar_decode is byte-faithful
6// (every field identical, byte length identical)
7// (c) 3 PROVENANCE CLASSES human / machine(tool+model) / downloaded(source URL) each encode,
8// store, and decode with the correct class + payload surviving
9// (d) INTEGRITY TEETH flip ONE byte of a stored record -> recomputed CID != the stored
10// key (tamper detected; content-address self-proof is load-bearing)
11//
12// Verdict logged to knowledge/status/asset_record_gate.log (append-only; ADDITIVE law #13).
13// expect_exit: 0 license_tier: ORIGINAL
14import "nx_syscalls.nx"
15import "nx_canon_cid.nx"
16import "nx_uxf_decode.nx"
17import "nx_seg_store.nx"
18import "nx_asset_record.nx"
19import "nx_gate_verdict.nx"
20
21// log fd is THREADED as a parameter (the compiler supports const globals but not
22// reassigning a module-level var from inside a function -- match the nx_blob_gate idiom).
23func g_puts(logfd: i64, s: *u8) -> i64 {
24 var n: i64 = 0
25 while s[n] != (0 as u8) { n = n + 1 }
26 sys_write(1, s, n)
27 if logfd > 0 { sys_write(logfd, s, n) }
28 return 0
29}
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}
45
46func g_streq(a: *u8, b: *u8) -> i64 {
47 var i: i64 = 0
48 while 1 == 1 {
49 if a[i] != b[i] { return 0 }
50 if a[i] == (0 as u8) { return 1 }
51 i = i + 1
52 }
53 return 1
54}
55
56// raw byte-for-byte equality of two buffers of equal length
57func g_memeq(a: *u8, b: *u8, n: i64) -> i64 {
58 var i: i64 = 0
59 while i < n { if a[i] != b[i] { return 0 } i = i + 1 }
60 return 1
61}
62
63// empty-string sentinel for omitted optional fields
64func E() -> *u8 { return "\x00" as *u8 }
65
66// set one slot of an i64 ptr-array to a string pointer
67func sset(a: *i64, i: i64, s: *u8) -> i64 { a[i] = s as i64; return 0 }
68
69// build a record from the 7 core / 6 prov / 4 media / 6 org fields -> canonical bytes into `out`;
70// returns byte length. (Grouped arrays keep us under the 16-arg call cap; ar_fields then ar_encode.)
71func mk_rec(core: *i64, prov: *i64, media: *i64, org: *i64, out: *u8) -> i64 {
72 let keys: *i64 = sys_mmap(8 * 48) as *i64
73 let vals: *i64 = sys_mmap(8 * 48) as *i64
74 let n: i64 = ar_fields(core, prov, media, org, keys, vals)
75 return ar_encode(keys, vals, n, out)
76}
77
78func main() -> i64 {
79 let logfd: i64 = sys_openat_append("knowledge/status/asset_record_gate.log\x00" as *u8, 0x1a4)
80 g_puts(logfd, "=== ASSET-RECORD-GATE (R0: unified content-addressed asset record) ===\n\x00" as *u8)
81
82 var pass: i64 = 0
83 var total: i64 = 0
84
85 // unique store prefix per run so the durable segmented store starts clean + idempotent
86 let prefix: *u8 = sys_mmap(256)
87 var po: i64 = 0
88 let pfx: *u8 = "/tmp/ar-\x00" as *u8
89 while pfx[po] != (0 as u8) { prefix[po] = pfx[po]; po = po + 1 }
90 let stamp: i64 = sys_now_ms()
91 var m: i64 = stamp
92 let ds: *u8 = sys_mmap(28)
93 var k: i64 = 0
94 if m == 0 { ds[0] = 48 as u8; k = 1 }
95 while m > 0 { ds[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
96 var j: i64 = 0
97 while j < k { prefix[po] = ds[k - 1 - j]; po = po + 1; j = j + 1 }
98 prefix[po] = 45 as u8; po = po + 1 // '-'
99 prefix[po] = 0 as u8
100
101 // ============================================================================================
102 // (a) DETERMINISTIC IDENTITY
103 // A MACHINE-generated image record (operator's generated-image case).
104 let pc: *u8 = sys_mmap(64)
105 let pa: *u8 = sys_mmap(64)
106 let pt: *u8 = sys_mmap(128)
107 let pm: *u8 = sys_mmap(128)
108 ar_prov_machine("nishi-gen-img\x00" as *u8, "sdxl-v1\x00" as *u8, pc, pa, pt, pm)
109
110 // core/prov/media/org grouped field arrays for the image record
111 let coreA: *i64 = sys_mmap(8 * 8) as *i64
112 sset(coreA, 0, "image\x00" as *u8); sset(coreA, 1, "Sunset over the lake\x00" as *u8)
113 sset(coreA, 2, "Nishi Studio\x00" as *u8); sset(coreA, 3, "2026-06-18\x00" as *u8)
114 sset(coreA, 4, "img-0001\x00" as *u8); sset(coreA, 5, "landscape\x00" as *u8); sset(coreA, 6, "CC-BY\x00" as *u8)
115 let provA: *i64 = sys_mmap(8 * 8) as *i64
116 sset(provA, 0, pc); sset(provA, 1, pa); sset(provA, 2, pt); sset(provA, 3, pm); sset(provA, 4, E()); sset(provA, 5, E())
117 let mediaA: *i64 = sys_mmap(8 * 8) as *i64
118 sset(mediaA, 0, "1920\x00" as *u8); sset(mediaA, 1, "1080\x00" as *u8); sset(mediaA, 2, E()); sset(mediaA, 3, "image/png\x00" as *u8)
119 let orgA: *i64 = sys_mmap(8 * 8) as *i64
120 sset(orgA, 0, "sunset,lake,landscape\x00" as *u8); sset(orgA, 1, "/volume1/assets/img-0001.png\x00" as *u8)
121 sset(orgA, 2, "manage\x00" as *u8); sset(orgA, 3, "1\x00" as *u8); sset(orgA, 4, "private\x00" as *u8); sset(orgA, 5, E())
122
123 let recA: *u8 = sys_mmap(8192)
124 let lenA: i64 = mk_rec(coreA, provA, mediaA, orgA, recA)
125 let cidA: *u8 = sys_mmap(128)
126 ar_cid(recA, lenA, cidA)
127 g_puts(logfd, " recA bytes=\x00" as *u8); g_putn(logfd, lenA); g_puts(logfd, " CID=\x00" as *u8); g_puts(logfd, cidA); g_puts(logfd, "\n\x00" as *u8)
128
129 // identical fields, fresh arrays + reversed-insertion to PROVE order-independence -> SAME CID.
130 let coreA2: *i64 = sys_mmap(8 * 8) as *i64
131 sset(coreA2, 6, "CC-BY\x00" as *u8); sset(coreA2, 5, "landscape\x00" as *u8); sset(coreA2, 4, "img-0001\x00" as *u8)
132 sset(coreA2, 3, "2026-06-18\x00" as *u8); sset(coreA2, 2, "Nishi Studio\x00" as *u8)
133 sset(coreA2, 1, "Sunset over the lake\x00" as *u8); sset(coreA2, 0, "image\x00" as *u8)
134 let recA2: *u8 = sys_mmap(8192)
135 let lenA2: i64 = mk_rec(coreA2, provA, mediaA, orgA, recA2)
136 let cidA2: *u8 = sys_mmap(128)
137 ar_cid(recA2, lenA2, cidA2)
138
139 total = total + 1
140 g_puts(logfd, " (a1) same fields -> same CID: \x00" as *u8)
141 if g_streq(cidA, cidA2) == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
142
143 // ONE field changed (title "Sunset"->"Sunrise"), everything else identical -> DIFFERENT CID
144 let coreB: *i64 = sys_mmap(8 * 8) as *i64
145 sset(coreB, 0, "image\x00" as *u8); sset(coreB, 1, "Sunrise over the lake\x00" as *u8)
146 sset(coreB, 2, "Nishi Studio\x00" as *u8); sset(coreB, 3, "2026-06-18\x00" as *u8)
147 sset(coreB, 4, "img-0001\x00" as *u8); sset(coreB, 5, "landscape\x00" as *u8); sset(coreB, 6, "CC-BY\x00" as *u8)
148 let recB: *u8 = sys_mmap(8192)
149 let lenB: i64 = mk_rec(coreB, provA, mediaA, orgA, recB)
150 let cidB: *u8 = sys_mmap(128)
151 ar_cid(recB, lenB, cidB)
152 g_puts(logfd, " recB (title changed) CID=\x00" as *u8); g_puts(logfd, cidB); g_puts(logfd, "\n\x00" as *u8)
153
154 total = total + 1
155 g_puts(logfd, " (a2) changed field -> different CID: \x00" as *u8)
156 if g_streq(cidA, cidB) == 0 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
157
158 // ============================================================================================
159 // (b) ROUND-TRIP: encode -> put -> get -> decode is byte-faithful
160 let prc: i64 = ar_put(prefix, recA, lenA)
161 total = total + 1
162 g_puts(logfd, " (b1) ar_put recA rc=\x00" as *u8); g_putn(logfd, prc); g_puts(logfd, ": \x00" as *u8)
163 if prc == 0 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
164
165 let gp: *i64 = sys_mmap(16) as *i64
166 let gl: *i64 = sys_mmap(16) as *i64
167 let gr: i64 = ar_get_by_cid(prefix, cidA, gp, gl)
168 total = total + 1
169 g_puts(logfd, " (b2) ar_get_by_cid rc=\x00" as *u8); g_putn(logfd, gr); g_puts(logfd, " len=\x00" as *u8); g_putn(logfd, gl[0])
170 g_puts(logfd, " (want \x00" as *u8); g_putn(logfd, lenA); g_puts(logfd, "): \x00" as *u8)
171 var got_ok: i64 = 0
172 if gr == 1 { if gl[0] == lenA { got_ok = 1 } }
173 if got_ok == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
174
175 // raw stored bytes identical to the encoded bytes
176 total = total + 1
177 g_puts(logfd, " (b3) stored bytes byte-faithful: \x00" as *u8)
178 var bytes_ok: i64 = 0
179 if got_ok == 1 { if g_memeq(gp[0] as *u8, recA, lenA) == 1 { bytes_ok = 1 } }
180 if bytes_ok == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
181
182 // decode the retrieved bytes and check every field equals the originals
183 let dk: *i64 = sys_mmap(8 * 48) as *i64
184 let dv: *i64 = sys_mmap(8 * 48) as *i64
185 let nf: i64 = ar_decode(gp[0] as *u8, gl[0], dk, dv, 40)
186 total = total + 1
187 g_puts(logfd, " (b4) decoded fields nf=\x00" as *u8); g_putn(logfd, nf); g_puts(logfd, ": \x00" as *u8)
188 var fields_ok: i64 = 1
189 if nf < 0 { fields_ok = 0 }
190 if fields_ok == 1 {
191 if g_streq(ar_get(dk, dv, nf, "type\x00" as *u8), "image\x00" as *u8) == 0 { fields_ok = 0 }
192 if g_streq(ar_get(dk, dv, nf, "title\x00" as *u8), "Sunset over the lake\x00" as *u8) == 0 { fields_ok = 0 }
193 if g_streq(ar_get(dk, dv, nf, "creator\x00" as *u8), "Nishi Studio\x00" as *u8) == 0 { fields_ok = 0 }
194 if g_streq(ar_get(dk, dv, nf, "width\x00" as *u8), "1920\x00" as *u8) == 0 { fields_ok = 0 }
195 if g_streq(ar_get(dk, dv, nf, "height\x00" as *u8), "1080\x00" as *u8) == 0 { fields_ok = 0 }
196 if g_streq(ar_get(dk, dv, nf, "classification\x00" as *u8), "private\x00" as *u8) == 0 { fields_ok = 0 }
197 if g_streq(ar_get(dk, dv, nf, "is_current\x00" as *u8), "1\x00" as *u8) == 0 { fields_ok = 0 }
198 }
199 if fields_ok == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
200
201 // ============================================================================================
202 // (c) 3 PROVENANCE CLASSES round-trip with correct class + payload
203
204 // -- (c1) HUMAN-authored doc --
205 let hc: *u8 = sys_mmap(64)
206 let ha: *u8 = sys_mmap(64)
207 ar_prov_human("Elder Westover\x00" as *u8, hc, ha)
208 let coreH: *i64 = sys_mmap(8 * 8) as *i64
209 sset(coreH, 0, "doc\x00" as *u8); sset(coreH, 1, "Family charter\x00" as *u8)
210 sset(coreH, 2, "Elder Westover\x00" as *u8); sset(coreH, 3, "2026-06-18\x00" as *u8)
211 sset(coreH, 4, E()); sset(coreH, 5, "governance\x00" as *u8); sset(coreH, 6, E())
212 let provH: *i64 = sys_mmap(8 * 8) as *i64
213 sset(provH, 0, hc); sset(provH, 1, ha); sset(provH, 2, E()); sset(provH, 3, E()); sset(provH, 4, E()); sset(provH, 5, E())
214 let mediaH: *i64 = sys_mmap(8 * 8) as *i64
215 sset(mediaH, 0, E()); sset(mediaH, 1, E()); sset(mediaH, 2, E()); sset(mediaH, 3, E())
216 let orgH: *i64 = sys_mmap(8 * 8) as *i64
217 sset(orgH, 0, "charter,family\x00" as *u8); sset(orgH, 1, "/volume1/docs/charter.md\x00" as *u8)
218 sset(orgH, 2, "use\x00" as *u8); sset(orgH, 3, "1\x00" as *u8); sset(orgH, 4, "professional\x00" as *u8); sset(orgH, 5, E())
219 let recH: *u8 = sys_mmap(8192)
220 let lenH: i64 = mk_rec(coreH, provH, mediaH, orgH, recH)
221 let dkh: *i64 = sys_mmap(8 * 48) as *i64
222 let dvh: *i64 = sys_mmap(8 * 48) as *i64
223 let nfh: i64 = ar_decode(recH, lenH, dkh, dvh, 40)
224 total = total + 1
225 g_puts(logfd, " (c1) HUMAN class survives [class=\x00" as *u8); g_puts(logfd, ar_get(dkh, dvh, nfh, "prov_class\x00" as *u8))
226 g_puts(logfd, " agent=\x00" as *u8); g_puts(logfd, ar_get(dkh, dvh, nfh, "prov_agent\x00" as *u8)); g_puts(logfd, "]: \x00" as *u8)
227 var h_ok: i64 = 1
228 if g_streq(ar_get(dkh, dvh, nfh, "prov_class\x00" as *u8), "human\x00" as *u8) == 0 { h_ok = 0 }
229 if g_streq(ar_get(dkh, dvh, nfh, "prov_agent\x00" as *u8), "Elder Westover\x00" as *u8) == 0 { h_ok = 0 }
230 // a human record carries NO tool/source
231 if ar_present(ar_get(dkh, dvh, nfh, "prov_tool\x00" as *u8)) == 1 { h_ok = 0 }
232 if ar_present(ar_get(dkh, dvh, nfh, "prov_source\x00" as *u8)) == 1 { h_ok = 0 }
233 if h_ok == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
234
235 // -- (c2) MACHINE-generated: tool + model must survive (reuse recA's machine prov, decode it) --
236 total = total + 1
237 g_puts(logfd, " (c2) MACHINE class+tool+model survive [class=\x00" as *u8); g_puts(logfd, ar_get(dk, dv, nf, "prov_class\x00" as *u8))
238 g_puts(logfd, " tool=\x00" as *u8); g_puts(logfd, ar_get(dk, dv, nf, "prov_tool\x00" as *u8))
239 g_puts(logfd, " model=\x00" as *u8); g_puts(logfd, ar_get(dk, dv, nf, "prov_model\x00" as *u8)); g_puts(logfd, "]: \x00" as *u8)
240 var mac_ok: i64 = 1
241 if g_streq(ar_get(dk, dv, nf, "prov_class\x00" as *u8), "machine\x00" as *u8) == 0 { mac_ok = 0 }
242 if g_streq(ar_get(dk, dv, nf, "prov_tool\x00" as *u8), "nishi-gen-img\x00" as *u8) == 0 { mac_ok = 0 }
243 if g_streq(ar_get(dk, dv, nf, "prov_model\x00" as *u8), "sdxl-v1\x00" as *u8) == 0 { mac_ok = 0 }
244 if mac_ok == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
245
246 // -- (c3) DOWNLOADED video: source URL must survive --
247 let dc: *u8 = sys_mmap(64)
248 let da: *u8 = sys_mmap(64)
249 let dsrc: *u8 = sys_mmap(256)
250 let ddate: *u8 = sys_mmap(64)
251 ar_prov_downloaded("https://example.com/clip.mp4\x00" as *u8, "2026-06-17\x00" as *u8, dc, da, dsrc, ddate)
252 let coreD: *i64 = sys_mmap(8 * 8) as *i64
253 sset(coreD, 0, "video\x00" as *u8); sset(coreD, 1, "Reference clip\x00" as *u8)
254 sset(coreD, 2, E()); sset(coreD, 3, E()); sset(coreD, 4, E()); sset(coreD, 5, E()); sset(coreD, 6, E())
255 let provD: *i64 = sys_mmap(8 * 8) as *i64
256 sset(provD, 0, dc); sset(provD, 1, da); sset(provD, 2, E()); sset(provD, 3, E()); sset(provD, 4, dsrc); sset(provD, 5, ddate)
257 let mediaD: *i64 = sys_mmap(8 * 8) as *i64
258 sset(mediaD, 0, "1280\x00" as *u8); sset(mediaD, 1, "720\x00" as *u8); sset(mediaD, 2, "00:02:31\x00" as *u8); sset(mediaD, 3, "video/mp4\x00" as *u8)
259 let orgD: *i64 = sys_mmap(8 * 8) as *i64
260 sset(orgD, 0, "reference\x00" as *u8); sset(orgD, 1, "/volume1/dl/clip.mp4\x00" as *u8)
261 sset(orgD, 2, "ingest\x00" as *u8); sset(orgD, 3, "1\x00" as *u8); sset(orgD, 4, "private\x00" as *u8); sset(orgD, 5, E())
262 let recD: *u8 = sys_mmap(8192)
263 let lenD: i64 = mk_rec(coreD, provD, mediaD, orgD, recD)
264 // round-trip through the STORE too (put -> get -> decode) to prove durability of a downloaded asset
265 let cidD: *u8 = sys_mmap(128)
266 ar_cid(recD, lenD, cidD)
267 ar_put(prefix, recD, lenD)
268 let dgp: *i64 = sys_mmap(16) as *i64
269 let dgl: *i64 = sys_mmap(16) as *i64
270 let dgr: i64 = ar_get_by_cid(prefix, cidD, dgp, dgl)
271 let dkd: *i64 = sys_mmap(8 * 48) as *i64
272 let dvd: *i64 = sys_mmap(8 * 48) as *i64
273 var nfd: i64 = 0 - 1
274 if dgr == 1 { nfd = ar_decode(dgp[0] as *u8, dgl[0], dkd, dvd, 40) }
275 total = total + 1
276 g_puts(logfd, " (c3) DOWNLOADED class+source survive store r/t [class=\x00" as *u8)
277 if nfd > 0 { g_puts(logfd, ar_get(dkd, dvd, nfd, "prov_class\x00" as *u8)) }
278 g_puts(logfd, " source=\x00" as *u8)
279 if nfd > 0 { g_puts(logfd, ar_get(dkd, dvd, nfd, "prov_source\x00" as *u8)) }
280 g_puts(logfd, "]: \x00" as *u8)
281 var dl_ok: i64 = 0
282 if nfd > 0 {
283 dl_ok = 1
284 if g_streq(ar_get(dkd, dvd, nfd, "prov_class\x00" as *u8), "downloaded\x00" as *u8) == 0 { dl_ok = 0 }
285 if g_streq(ar_get(dkd, dvd, nfd, "prov_source\x00" as *u8), "https://example.com/clip.mp4\x00" as *u8) == 0 { dl_ok = 0 }
286 if g_streq(ar_get(dkd, dvd, nfd, "prov_date\x00" as *u8), "2026-06-17\x00" as *u8) == 0 { dl_ok = 0 }
287 // a downloaded record carries NO tool/model
288 if ar_present(ar_get(dkd, dvd, nfd, "prov_tool\x00" as *u8)) == 1 { dl_ok = 0 }
289 }
290 if dl_ok == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
291
292 // ============================================================================================
293 // (d) INTEGRITY TEETH: flip ONE byte of the stored record -> recomputed CID != the stored key.
294 // Copy the stored bytes, corrupt one byte in the middle, recompute its CID, assert mismatch.
295 let n5: i64 = gl[0]
296 let tampered: *u8 = sys_mmap(n5 + 16)
297 var c5: i64 = 0
298 // LM-031 fix: bind the cast to a local, then index. The inline form `(gp[0] as *u8)[c5]` SILENTLY MISCOMPILES
299 // to a garbage pointer-sized value (found by nx_doc_ubscan, confirmed by nx_ub_verify: inline=garbage vs
300 // bind-then-index=correct) -- so this tamper test was copying GARBAGE, passing for the wrong reason.
301 let rec_src: *u8 = gp[0] as *u8
302 while c5 < n5 { tampered[c5] = rec_src[c5]; c5 = c5 + 1 }
303 let mid5: i64 = n5 / 2
304 tampered[mid5] = (tampered[mid5] ^ (1 as u8)) as u8 // flip one bit of one byte
305 let cidT: *u8 = sys_mmap(128)
306 ar_cid(tampered, n5, cidT)
307 g_puts(logfd, " tampered byte@\x00" as *u8); g_putn(logfd, mid5); g_puts(logfd, " recomputed CID=\x00" as *u8); g_puts(logfd, cidT); g_puts(logfd, "\n\x00" as *u8)
308 total = total + 1
309 g_puts(logfd, " (d) flipped byte -> CID no longer matches stored key (tamper detected): \x00" as *u8)
310 if g_streq(cidT, cidA) == 0 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
311
312 // also: the tampered bytes must NOT resolve in the store under the original key as themselves
313 // (the store key IS cidA; the tampered content's own CID is cidT != cidA -> integrity by address)
314 total = total + 1
315 g_puts(logfd, " (d2) tampered content's CID differs from BOTH stored keys (A,D): \x00" as *u8)
316 var teeth2: i64 = 1
317 if g_streq(cidT, cidA) == 1 { teeth2 = 0 }
318 if g_streq(cidT, cidD) == 1 { teeth2 = 0 }
319 if teeth2 == 1 { pass = pass + 1; g_puts(logfd, "PASS\n\x00" as *u8) } else { g_puts(logfd, "FAIL\n\x00" as *u8) }
320
321 // ============================================================================================
322 g_puts(logfd, "ASSET-RECORD-GATE passed \x00" as *u8); g_putn(logfd, pass); g_puts(logfd, "/\x00" as *u8); g_putn(logfd, total)
323 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
324 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
325 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
326 let ctr__dry: *i64 = gv_ctr()
327 ctr__dry[0] = pass
328 ctr__dry[1] = total
329 let rc__dry: i64 = gv_verdict("ASSET-RECORD-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
330 sys_exit(rc__dry)
331 return rc__dry
332}