code wiki / _hdl_build / nx_ss_verify_gate.nx
nx_ss_verify_gate.nx source
↩ module page · 154 lines · 7406 B
1import "nx_gate_verdict.nx"
2import "nx_seg_store.nx"
3import "nx_syscalls.nx"
4// nx_ss_verify_gate.nx -- BITE gate for ss_verify_merged (verify-then-commit, 2026-08-07).
5//
6// WHY THIS EXISTS. ss_verify_merged was added so the compactor re-reads the segment it just wrote and
7// proves it reproduces the merged table BEFORE the manifest swap. Running the compaction gate with it
8// active showed 9/9 GREEN -- but an ss_verify_merged that unconditionally returned 0 would produce
9// byte-identical output. ★A GUARD THAT HAS ONLY EVER PASSED IS UNVERIFIED. So every tooth below is a
10// gv_bite: the verifier must FIRE on a crafted disagreement AND stay SILENT on the exact match. A
11// green here means the check is real, not merely present.
12//
13// CONSTRUCTION. A segment is written from a table this gate builds itself, so the table and the
14// artifact are known to agree by construction; each bite then perturbs ONE field, runs the verifier,
15// restores the field, and runs it again. The restore-and-re-pass is what proves the RED came from the
16// mutation and not from state the previous tooth damaged -- the failure mode that made
17// _ss_compact_cap_gate green exactly once.
18//
19// Verdict emission INHERITS nx_gate_verdict (D001): this gate does not roll its own, so nx_gate_green
20// can judge it and it records a harness frame.
21// license_tier: ORIGINAL No hw writes (Rule 26).
22
23const SSV_K: i64 = 64
24const SSV_SEGID: i64 = 700001
25const SSV_ABSENT_SEGID: i64 = 700999
26const SSV_KLEN: i64 = 6
27const SSV_VLEN: i64 = 5
28const SSV_DIRMODE: i64 = 0x1ed
29const SSV_PROBE_I: i64 = 7
30const SSV_KIND_I: i64 = 9
31const SSV_KLEN_I: i64 = 13
32
33// "vk:NNN" -- 6 bytes, null-terminated
34func ssv_kbuf(n: i64, out: *u8) -> i64 {
35 out[0] = 118 as u8
36 out[1] = 107 as u8
37 out[2] = 58 as u8
38 out[3] = (48 + (n / 100) % 10) as u8
39 out[4] = (48 + (n / 10) % 10) as u8
40 out[5] = (48 + n % 10) as u8
41 out[6] = 0 as u8
42 return SSV_KLEN
43}
44// "vvNNN" -- 5 bytes, null-terminated
45func ssv_vbuf(n: i64, out: *u8) -> i64 {
46 out[0] = 118 as u8
47 out[1] = 118 as u8
48 out[2] = (48 + (n / 100) % 10) as u8
49 out[3] = (48 + (n / 10) % 10) as u8
50 out[4] = (48 + n % 10) as u8
51 out[5] = 0 as u8
52 return SSV_VLEN
53}
54
55// run the verifier against the CURRENT table state; 1 = it fired (disagreed), 0 = it was silent
56func ssv_fired(prefix: *u8, segid: i64, tkp: *i64, tkl: *i64, tkind: *i64, tvp: *i64, tvl: *i64, nk: i64, hidx: *i64, hcap: i64) -> i64 {
57 if ss_verify_merged(prefix, segid, tkp, tkl, tkind, tvp, tvl, nk, hidx, hcap) != 0 { return 1 }
58 return 0
59}
60
61func main() -> i64 {
62 let ctr: *i64 = gv_ctr()
63 gv_head("nx_ss_verify_gate -- ss_verify_merged must FIRE on a segment that disagrees with the merged table, and stay SILENT on one that agrees" as *u8)
64
65 sys_mkdir("/tmp/ssvgate\x00" as *u8, SSV_DIRMODE)
66 let prefix: *u8 = "/tmp/ssvgate/_ssv-" as *u8
67
68 let tkp: *i64 = sys_mmap(8 * SSV_K) as *i64
69 let tkl: *i64 = sys_mmap(8 * SSV_K) as *i64
70 let tkind: *i64 = sys_mmap(8 * SSV_K) as *i64
71 let tvp: *i64 = sys_mmap(8 * SSV_K) as *i64
72 let tvl: *i64 = sys_mmap(8 * SSV_K) as *i64
73 var hcap: i64 = 16
74 while hcap < SSV_K * 2 { hcap = hcap * 2 }
75 let hidx: *i64 = sys_mmap(8 * hcap) as *i64
76
77 // build the table AND the segment from the same source, so they agree by construction
78 let w: *i64 = ss_begin()
79 var i: i64 = 0
80 while i < SSV_K {
81 let kb: *u8 = sys_mmap(16)
82 let vb: *u8 = sys_mmap(16)
83 ssv_kbuf(i, kb)
84 ssv_vbuf(i, vb)
85 tkp[i] = kb as i64
86 tkl[i] = SSV_KLEN
87 tkind[i] = 1
88 tvp[i] = vb as i64
89 tvl[i] = SSV_VLEN
90 var probe: i64 = ss_khash(kb, SSV_KLEN) & (hcap - 1)
91 while hidx[probe] != 0 { probe = (probe + 1) & (hcap - 1) }
92 hidx[probe] = i + 1
93 ss_add2(w, 1, kb, SSV_KLEN, vb, SSV_VLEN)
94 i = i + 1
95 }
96 if ss_write_seg(prefix, w, SSV_SEGID) != 0 {
97 gv_puts("SETUP FAIL: cannot write the fixture segment\
98" as *u8)
99 sys_exit(1)
100 return 1
101 }
102
103 // ---- T1: the exact match must be accepted (the control every bite below is measured against)
104 var t1: i64 = 0
105 if ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap) == 0 { t1 = 1 }
106 gv_check("T1 accepts a segment that matches its table exactly" as *u8, t1, ctr)
107
108 // ---- T2: key COUNT too high == a key vanished from the output. This is the tooth a per-record
109 // check cannot have: every record present still verifies, so only the count sees the loss.
110 let b2: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K + 1, hidx, hcap)
111 let g2: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
112 gv_bite("T2 fires when a key is MISSING from the output (count too high)" as *u8, b2, g2, ctr)
113
114 // ---- T3: key COUNT too low == the writer emitted a key twice
115 let b3: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K - 1, hidx, hcap)
116 let g3: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
117 gv_bite("T3 fires when a key is DUPLICATED in the output (count too low)" as *u8, b3, g3, ctr)
118
119 // ---- T4: one VALUE byte differs. Size-preserving by construction -- a byte count cannot see it.
120 let vb4: *u8 = tvp[SSV_PROBE_I] as *u8
121 let sv4: i64 = vb4[2] as i64
122 vb4[2] = (sv4 + 1) as u8
123 let b4: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
124 vb4[2] = sv4 as u8
125 let g4: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
126 gv_bite("T4 fires on a single differing VALUE byte (same length)" as *u8, b4, g4, ctr)
127
128 // ---- T5: KIND differs (a put recorded where a tombstone belongs, or the reverse)
129 let sv5: i64 = tkind[SSV_KIND_I]
130 tkind[SSV_KIND_I] = 2
131 let b5: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
132 tkind[SSV_KIND_I] = sv5
133 let g5: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
134 gv_bite("T5 fires when a record KIND disagrees (put vs tombstone)" as *u8, b5, g5, ctr)
135
136 // ---- T6: a key in the output is not findable in the table (key length corrupted so ss_kcmp
137 // misses). Proves the probe REFUSES rather than silently accepting an unmatched record.
138 let sv6: i64 = tkl[SSV_KLEN_I]
139 tkl[SSV_KLEN_I] = SSV_KLEN - 1
140 let b6: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
141 tkl[SSV_KLEN_I] = sv6
142 let g6: i64 = ssv_fired(prefix, SSV_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap)
143 gv_bite("T6 fires when an output key is UNFINDABLE in the table" as *u8, b6, g6, ctr)
144
145 // ---- T7: a missing artifact must REFUSE, never pass by vacuous absence. This is the tooth that
146 // catches the whole class where nothing ran at all and the check reported success.
147 var t7: i64 = 0
148 if ssv_fired(prefix, SSV_ABSENT_SEGID, tkp, tkl, tkind, tvp, tvl, SSV_K, hidx, hcap) == 1 { t7 = 1 }
149 gv_check("T7 refuses when the segment file is ABSENT (no vacuous pass)" as *u8, t7, ctr)
150
151 let rc: i64 = gv_verdict("SS-VERIFY-GATE" as *u8, ctr, "ss_verify_merged fires on missing/duplicated keys, a differing value byte, a wrong kind, an unfindable key and an absent artifact -- and is silent on the exact match" as *u8)
152 sys_exit(rc)
153 return rc
154}