code wiki / _hdl_build / nx_sov_guard2.nx
nx_sov_guard2.nx source
↩ module page · 260 lines · 12174 B
1// nx_sov_guard2.nx -- the NO-NEW-TSV law with a WORKING TOOTH (eats seq279 at the root).
2//
3// WHY A REWRITE, NOT A PATCH (rule 3): v1 scanned exactly ONE directory and defaulted to `knowledge/status`,
4// so `knowledge/registry` -- which holds ~150 .tsv including the 3 this session created -- was NEVER SCANNED.
5// The law existed, the organ existed, the allowlist existed, and none of it could fire on the directory that
6// mattered. A guard that cannot see the violation is not a guard.
7//
8// TWO STRUCTURAL FIXES:
9// 1. MULTI-DIR, DATA-DRIVEN scan-set. Dirs come from the native plane knowledge/store/sovguard- (`dir<TAB>path`
10// rows) -- rule 11, and pointedly NOT from a .tsv (the anti-tsv guard configuring itself with a tsv would be
11// the joke that writes itself). If the plane is absent the organ still guards using a compiled-in default set
12// and DECLARES `config:default-set` -- fail-SAFE, because a guard that silently stops guarding is worse than
13// one that guards loudly with defaults.
14// 2. RATCHET, not a cliff. ~150 legacy files exist; a plain count>0 rule would be RED forever and get ignored
15// (an alarm nobody can silence is an alarm nobody hears). Instead we compare against a recorded BASELINE and
16// fail ONLY when the count RISES -- which is exactly what "no NEW tsv" means. Legacy shrinks lane by lane;
17// a new file trips it the same day. Same snapshot/check idiom as nx_tooldiff / nx_route_diff.
18//
19// nx_sov_guard2 check -> GREEN if count <= baseline; RED (exit 1) naming the NEW files if it rose
20// nx_sov_guard2 snapshot -> deliberately re-record the baseline (after a migration lands)
21// Emits knowledge/status/sov_guard.log with a VERDICT line for the reliability plane.
22// license_tier: ORIGINAL expect_exit: 0
23import "nx_store_seed_lib.nx"
24import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
25import "nx_seg_store.nx"
26import "nx_syscalls.nx"
27const SG2_MAGIC_65536: i64 = 65536
28const SG2_MAGIC_4096: i64 = 4096
29const SG2_MAGIC_1024: i64 = 1024
30const SG2_MAGIC_262144: i64 = 262144
31
32const SG2_PLANE: *u8 = "knowledge/store/sovguard-"
33const SG2_ALLOW: *u8 = "knowledge/registry/tsv_allow.list"
34const SG2_LOG: *u8 = "knowledge/status/sov_guard.log"
35const SG2_CAP: i64 = 1048576
36
37func sg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
38// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
39// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
40// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
41// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
42func sg_wn(v: i64) -> i64 { nxi_out(v); return 0 }
43func sg_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
44func sg_cat(o: *u8, at: i64, s: *u8) -> i64 { var i: i64=0; var a: i64=at; while s[i]!=(0 as u8){o[a]=s[i]; a=a+1; i=i+1} return a }
45func sg_catn(o: *u8, at: i64, v: i64) -> i64 {
46 var a: i64=at; var x: i64=v
47 if x<0 { o[a]=45 as u8; a=a+1; x=0-x }
48 let tm: *u8=sys_mmap(24); var k: i64=0
49 if x==0 { tm[0]=48 as u8; k=1 }
50 while x>0 { tm[k]=(48+x%10) as u8; x=x/10; k=k+1 }
51 var j: i64=0
52 while j<k { o[a]=tm[k-1-j]; a=a+1; j=j+1 }
53 return a
54}
55func sg_ends(name: *u8, suf: *u8) -> i64 {
56 let n: i64=sg_slen(name); let s: i64=sg_slen(suf)
57 if n<s { return 0 }
58 var i: i64=0
59 while i<s { if name[n-s+i]!=suf[i] { return 0 } i=i+1 }
60 return 1
61}
62func sg_readfile(path: *u8, buf: *u8, cap: i64) -> i64 {
63 let fd: i64=sys_openat_rd(path)
64 if fd<0 { return 0 }
65 var off: i64=0; var go: i64=1
66 while go==1 { if off>=cap { go=0 } else { let r: i64=sys_read(fd, (buf as i64+off) as *u8, cap-off); if r<=0 { go=0 } else { off=off+r } } }
67 sys_close(fd)
68 return off
69}
70// exact non-# line match
71func sg_line_in(buf: *u8, n: i64, name: *u8) -> i64 {
72 let nl: i64=sg_slen(name)
73 var ls: i64=0; var i: i64=0
74 while i<=n {
75 var eol: i64=0
76 if i>=n { eol=1 } else { if buf[i]==(10 as u8) { eol=1 } }
77 if eol==1 {
78 let llen: i64=i-ls
79 if llen==nl { if buf[ls]!=(35 as u8) {
80 var m: i64=0; var ok: i64=1
81 while m<nl { if buf[ls+m]!=name[m] { ok=0; m=nl } else { m=m+1 } }
82 if ok==1 { return 1 }
83 } }
84 ls=i+1
85 }
86 i=i+1
87 }
88 return 0
89}
90// scan ONE dir; appends violating names to `names` (bounded); returns violation count, -1 unopenable
91func sg_scan_dir(dir: *u8, allow: *u8, an: i64, names: *u8, no: *i64, shown: *i64) -> i64 {
92 let dfd: i64 = __syscall(257, 0-100, dir, 0x10000, 0, 0, 0)
93 if dfd<0 { return 0-1 }
94 let buf: *u8=sys_mmap(SG2_MAGIC_65536)
95 let nm: *u8=sys_mmap(512)
96 var viol: i64=0
97 var go: i64=1
98 while go==1 {
99 let nread: i64 = __syscall(217, dfd, buf, SG2_MAGIC_65536, 0, 0, 0)
100 if nread<=0 { go=0 } else {
101 var pos: i64=0
102 while pos<nread {
103 let reclen: i64=(buf[pos+16] as i64)|((buf[pos+17] as i64)<<8)
104 let dtype: i64=buf[pos+18] as i64
105 var nl: i64=0
106 while buf[pos+19+nl]!=(0 as u8) { nm[nl]=buf[pos+19+nl]; nl=nl+1 }
107 nm[nl]=0 as u8
108 if dtype==8 { if sg_ends(nm, ".tsv\x00" as *u8)==1 {
109 if sg_line_in(allow, an, nm)==0 {
110 viol=viol+1
111 if shown[0]<12 {
112 var o: i64=no[0]
113 o=sg_cat(names, o, dir); names[o]=47 as u8; o=o+1
114 o=sg_cat(names, o, nm); names[o]=10 as u8; o=o+1
115 no[0]=o
116 shown[0]=shown[0]+1
117 }
118 }
119 } }
120 if reclen<=0 { pos=nread } else { pos=pos+reclen }
121 }
122 }
123 }
124 sys_close(dfd)
125 return viol
126}
127
128func main(argc: i64, argv: *i64) -> i64 {
129 var verb: *u8 = "check\x00" as *u8
130 if argc>=2 { verb = argv[1] as *u8 }
131 // ---- scan-set + baseline from the NATIVE plane (never a .tsv), else declared defaults
132 let pb: *u8=sys_mmap(SG2_CAP)
133 let pn: i64=sts_load(SG2_PLANE, pb, SG2_CAP-SG2_MAGIC_4096)
134 let dirs: *i64=sys_mmap(SG2_MAGIC_1024) as *i64
135 let dbuf: *u8=sys_mmap(SG2_MAGIC_65536)
136 var ndir: i64=0
137 var baseline: i64=0-1
138 var cfg: *u8="plane\x00" as *u8
139 var dbo: i64=0
140 if pn>0 {
141 var i: i64=0
142 while i<pn {
143 let ls: i64=i
144 var le: i64=ls
145 var sc: i64=1
146 while sc==1 { if le>=pn { sc=0 } else { if pb[le]==(10 as u8) { sc=0 } else { le=le+1 } } }
147 i=le+1
148 if le>ls {
149 // split at first TAB
150 var t: i64=ls
151 var found: i64=0-1
152 while t<le { if pb[t]==(9 as u8) { if found<0 { found=t } } t=t+1 }
153 if found>0 {
154 let klen: i64=found-ls
155 let vs: i64=found+1
156 let vlen: i64=le-vs
157 // key "dir"
158 if klen==3 { if pb[ls]==(100 as u8) { if pb[ls+1]==(105 as u8) { if pb[ls+2]==(114 as u8) {
159 if ndir<64 { if dbo+vlen+2<SG2_MAGIC_65536 {
160 dirs[ndir]=(dbuf as i64)+dbo
161 var k: i64=0
162 while k<vlen { dbuf[dbo]=pb[vs+k]; dbo=dbo+1; k=k+1 }
163 dbuf[dbo]=0 as u8; dbo=dbo+1
164 ndir=ndir+1
165 } }
166 } } } }
167 // key "baseline"
168 if klen==8 { if pb[ls]==(98 as u8) {
169 var v: i64=0; var k: i64=0
170 while k<vlen { let c: i64=pb[vs+k] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } k=k+1 }
171 baseline=v
172 } }
173 }
174 }
175 }
176 }
177 if ndir==0 {
178 cfg="default-set\x00" as *u8
179 dirs[0]="knowledge/registry\x00" as *u8 as i64
180 dirs[1]="knowledge/status\x00" as *u8 as i64
181 ndir=2
182 }
183 // ---- scan
184 let allow: *u8=sys_mmap(SG2_MAGIC_262144)
185 let an: i64=sg_readfile(SG2_ALLOW, allow, SG2_MAGIC_262144)
186 let names: *u8=sys_mmap(SG2_MAGIC_65536)
187 let no: *i64=sys_mmap(16) as *i64
188 let shown: *i64=sys_mmap(16) as *i64
189 no[0]=0; shown[0]=0
190 var total: i64=0
191 var unopenable: i64=0
192 var d: i64=0
193 while d<ndir {
194 let v: i64=sg_scan_dir(dirs[d] as *u8, allow, an, names, no, shown)
195 if v<0 { unopenable=unopenable+1 } else { total=total+v }
196 d=d+1
197 }
198 names[no[0]]=0 as u8
199 // ---- snapshot: deliberately re-record the baseline into the native plane
200 if verb[0]==(115 as u8) {
201 let ob: *u8=sys_mmap(SG2_MAGIC_65536)
202 var o: i64=0
203 var k: i64=0
204 while k<ndir { o=sg_cat(ob, o, "dir\x09" as *u8); o=sg_cat(ob, o, dirs[k] as *u8); ob[o]=10 as u8; o=o+1; k=k+1 }
205 o=sg_cat(ob, o, "baseline\x09" as *u8); o=sg_catn(ob, o, total); ob[o]=10 as u8; o=o+1
206 let rc: i64=sts_seed(SG2_PLANE, ob, o)
207 sg_w("{\x22verb\x22:\x22snapshot\x22,\x22dirs\x22:" as *u8); sg_wn(ndir)
208 sg_w(",\x22unallowlisted_tsv\x22:" as *u8); sg_wn(total)
209 sg_w(",\x22baseline_recorded\x22:" as *u8); sg_wn(total)
210 sg_w(",\x22plane_rows\x22:" as *u8); sg_wn(rc)
211 sg_w("}\n" as *u8)
212 if rc<0 { sg_w("SOV-GUARD RED -- baseline commit failed\n" as *u8); sys_exit(2); return 2 }
213 sg_w("SOV-GUARD SNAPSHOT -- ratchet armed at the current count; any RISE is now a violation\n" as *u8)
214 return 0
215 }
216 // ---- check (the ratchet)
217 var eff: i64=baseline
218 var armed: i64=1
219 if baseline<0 { eff=total; armed=0 } // first ever run: adopt, declare UNARMED, never fake a pass
220 let delta: i64=total-eff
221 var red: i64=0
222 if delta>0 { red=1 }
223 sg_w("{\x22verb\x22:\x22check\x22,\x22config\x22:\x22" as *u8); sg_w(cfg)
224 sg_w("\x22,\x22dirs_scanned\x22:" as *u8); sg_wn(ndir)
225 sg_w(",\x22dirs_unopenable\x22:" as *u8); sg_wn(unopenable)
226 sg_w(",\x22unallowlisted_tsv\x22:" as *u8); sg_wn(total)
227 sg_w(",\x22baseline\x22:" as *u8); sg_wn(eff)
228 sg_w(",\x22delta\x22:" as *u8); sg_wn(delta)
229 sg_w(",\x22ratchet_armed\x22:" as *u8); sg_wn(armed)
230 sg_w(",\x22verdict\x22:\x22" as *u8)
231 if red==1 { sg_w("RED" as *u8) } else { sg_w("GREEN" as *u8) }
232 sg_w("\x22,\x22law\x22:\x22no NEW tsv -- legacy shrinks lane by lane, but the count must never RISE\x22}\n" as *u8)
233 if no[0]>0 { sg_w("unallowlisted (first 12):\n" as *u8); sg_w(names) }
234 // ---- evidence for the reliability plane
235 let lf: i64=sys_openat_wr(SG2_LOG, 0x1a4)
236 if lf>=0 {
237 let lb: *u8=sys_mmap(SG2_MAGIC_4096)
238 var o: i64=0
239 o=sg_cat(lb, o, "nx_sov_guard2 -- no-new-tsv ratchet (config=" as *u8); o=sg_cat(lb, o, cfg)
240 o=sg_cat(lb, o, ")\n dirs_scanned=" as *u8); o=sg_catn(lb, o, ndir)
241 o=sg_cat(lb, o, " unallowlisted_tsv=" as *u8); o=sg_catn(lb, o, total)
242 o=sg_cat(lb, o, " baseline=" as *u8); o=sg_catn(lb, o, eff)
243 o=sg_cat(lb, o, " delta=" as *u8); o=sg_catn(lb, o, delta)
244 o=sg_cat(lb, o, " armed=" as *u8); o=sg_catn(lb, o, armed)
245 o=sg_cat(lb, o, "\nVERDICT=" as *u8)
246 if red==1 { o=sg_cat(lb, o, "RED" as *u8) } else { o=sg_cat(lb, o, "GREEN" as *u8) }
247 o=sg_cat(lb, o, "\n" as *u8)
248 sys_write(lf, lb, o)
249 if no[0]>0 { sys_write(lf, names, no[0]) }
250 sys_close(lf)
251 }
252 if red==1 {
253 sg_w("SOV-GUARD RED -- a NEW unallowlisted .tsv appeared (count rose above baseline). Migrate it with nx_tsv_migrate, or allowlist it with an owner note; re-snapshot only when the rise is intentional.\n" as *u8)
254 sys_exit(1)
255 return 1
256 }
257 if armed==0 { sg_w("SOV-GUARD GREEN (ratchet UNARMED -- no baseline recorded yet; run `snapshot` to arm it)\n" as *u8); return 0 }
258 sg_w("SOV-GUARD GREEN -- no new tsv since the baseline\n" as *u8)
259 return 0
260}