nx_unread_sensor.nx source
↩ module page · 256 lines · 11394 B
1// nx_unread_sensor.nx -- WHICH STATUS ARTIFACTS DOES NOTHING NAME.
2//
3// usage: nx_unread_sensor [statusdir] default knowledge/status/
4// exit: 0 GREEN (single-namer count at or below its ratchet) | 1 RED (it rose) | 3 UNPROVEN
5//
6// See nx_unread_sensor_lib.nx for why this exists and for the blind spots it declares. In short: this
7// estate rediscovered "a sensor nothing reads" four times in one day, and owned no instrument that could
8// have found the fifth. Every number below is a FLOOR on readers, so a row here is a QUESTION.
9//
10// IT REFUSES TO RUN ON A SATURATED BOX. Composing ct_admit_now costs one small /proc read and no fork,
11// and the alternative is a corpus-wide scan that becomes the load it was built to explain --
12// A DIAGNOSTIC THAT CANNOT REFUSE TO RUN IS A LOAD GENERATOR WITH GOOD INTENTIONS.
13//
14// THE RATCHET SELF-BASELINES ON FIRST SIGHT, so shipping it cannot turn every build red on day one, and
15// it is written ONLY on a fall or a first run: a ratchet that rewrites its baseline on a RISE launders
16// itself green and is worse than no ratchet at all.
17// license_tier: ORIGINAL expect_exit: 0 Read-only. No hw writes (Rule 26).
18import "nx_syscalls.nx"
19import "nx_gatekit_lib.nx"
20import "nx_ctxtop_lib.nx"
21import "nx_unread_sensor_lib.nx"
22
23const UR_MAXART: i64 = 512
24const UR_STRIDE: i64 = 96
25const UR_NAMES_BYTES: i64 = 49152 // UR_MAXART * UR_STRIDE
26const UR_I64_BYTES: i64 = 4096 // UR_MAXART * 8
27const UR_FILECAP: i64 = 262144
28const UR_PATHCAP: i64 = 1024
29const UR_CORPUS_STRIDE: i64 = 256
30const UR_DIRBUF: i64 = 65536
31const UR_DIRENT_NAME_OFF: i64 = 19
32const UR_BASELINE: *u8 = "knowledge/status/unread_sensor.baseline"
33const UR_BASELINE_NAME: *u8 = "unread_sensor.baseline"
34const UR_MODE_644: i64 = 420
35const UR_EXIT_GREEN: i64 = 0
36const UR_EXIT_RED: i64 = 1
37const UR_EXIT_UNPROVEN: i64 = 3
38const UR_NEEDLE: *u8 = "knowledge/status/"
39const UR_NEEDLE_LEN: i64 = 17
40
41func ur_puts(s: *u8) -> i64 { sys_write(1, s, us_len(s)); return 0 }
42func ur_num(v: i64) -> i64 {
43 let b: *u8 = sys_mmap(32)
44 var o: i64 = gk_catn(b, 0, v)
45 sys_write(1, b, o)
46 sys_munmap(b, 32)
47 return 0
48}
49
50func main(argc: i64, argv: *i64) -> i64 {
51 var sdir: *u8 = "knowledge/status/" as *u8
52 if argc >= 2 { sdir = argv[1] as *u8 }
53
54 // ---- ADMISSION FIRST, before a single corpus byte is read ----
55 if ct_admit_now() != 1 {
56 ur_puts("REFUSED-BUSY the box is saturated and this census reads the whole source corpus.\n" as *u8)
57 ur_puts("Nothing was scanned, so nothing is claimed. Re-run when load clears.\n" as *u8)
58 ur_puts("verdict=UNPROVEN\n" as *u8)
59 return UR_EXIT_UNPROVEN
60 }
61
62 // ---- 1. enumerate the status artifacts ----
63 let names: *u8 = sys_mmap(UR_NAMES_BYTES)
64 let refs: *i64 = sys_mmap(UR_I64_BYTES) as *i64
65 let lastsrc: *i64 = sys_mmap(UR_I64_BYTES) as *i64
66 var nart: i64 = 0
67 var art_full: i64 = 0
68 let dfd: i64 = sys_openat_rd(sdir)
69 if dfd < 0 {
70 ur_puts("STATUSDIR-UNREADABLE " as *u8); ur_puts(sdir); ur_puts("\n" as *u8)
71 ur_puts("verdict=UNPROVEN\n" as *u8)
72 return UR_EXIT_UNPROVEN
73 }
74 let db: *u8 = sys_mmap(UR_DIRBUF)
75 var go: i64 = 1
76 while go == 1 {
77 let nr: i64 = sys_getdents64(dfd, db, UR_DIRBUF)
78 if nr <= 0 { go = 0 }
79 if nr > 0 {
80 var pos: i64 = 0
81 while pos < nr {
82 let rec: *u8 = ((db as i64) + pos) as *u8
83 let rl: i64 = (rec[16] as i64) | ((rec[17] as i64) << 8)
84 if rl <= 0 { pos = nr }
85 if rl > 0 {
86 let nm: *u8 = ((rec as i64) + UR_DIRENT_NAME_OFF) as *u8
87 // '.' and '..' fail the name test on their own: a bare dot run is not an artifact.
88 if us_isnamechar(nm[0] as i64) == 1 {
89 if nm[0] != (US_DOT as u8) {
90 if nart < UR_MAXART {
91 let dst: *u8 = ((names as i64) + nart * UR_STRIDE) as *u8
92 var k: i64 = 0
93 while nm[k] != (0 as u8) { if k < UR_STRIDE - 1 { dst[k] = nm[k] } k = k + 1 }
94 dst[k] = 0 as u8
95 refs[nart] = 0
96 lastsrc[nart] = 0 - 1
97 nart = nart + 1
98 }
99 if nart >= UR_MAXART { art_full = 1 }
100 }
101 }
102 pos = pos + rl
103 }
104 }
105 }
106 }
107 sys_munmap(db, UR_DIRBUF)
108 sys_close(dfd)
109
110 // ---- 2. ONE pass over the .nx corpus, counting DISTINCT namers per artifact ----
111 let maxlen: *i64 = sys_mmap(64) as *i64
112 let ncorp: i64 = gk_corpus_count(maxlen)
113 if ncorp <= 0 {
114 ur_puts("CORPUS-UNREADABLE the source tree could not be enumerated, so absence cannot be proven.\n" as *u8)
115 ur_puts("verdict=UNPROVEN\n" as *u8)
116 return UR_EXIT_UNPROVEN
117 }
118 let paths: *u8 = sys_mmap(ncorp * UR_CORPUS_STRIDE + UR_CORPUS_STRIDE)
119 let got: i64 = gk_corpus_scan(paths, UR_CORPUS_STRIDE, ncorp + 1)
120 let fbuf: *u8 = sys_mmap(UR_FILECAP)
121 let tok: *u8 = sys_mmap(US_NAMECAP)
122 var scanned: i64 = 0
123 var truncated: i64 = 0
124 var unreadable: i64 = 0
125 var si: i64 = 0
126 while si < got {
127 let p: *u8 = ((paths as i64) + si * UR_CORPUS_STRIDE) as *u8
128 // THE READ IS SIZED FROM THE FILE, NOT FROM A CAP. The first cut used a 256 KB buffer and 8 of
129 // 19,391 sources overflowed it, turning a whole-corpus census into a partial one and making every
130 // absence UNPROVEN. The fix for a cap you hit is to MEASURE THE INPUT, never to pick a bigger
131 // number: sys_read_file lseeks to END, sizes its own buffer, and cannot short-read.
132 let flen: *i64 = sys_mmap(64) as *i64
133 let fb: *u8 = sys_read_file(p, flen)
134 if fb == (0 as *u8) { unreadable = unreadable + 1 }
135 if fb != (0 as *u8) {
136 let tot: i64 = flen[0]
137 let fbuf: *u8 = fb
138 scanned = scanned + 1
139 var at: i64 = 0
140 var fgo: i64 = 1
141 while fgo == 1 {
142 let h: i64 = us_find_from(fbuf, tot, at, UR_NEEDLE)
143 if h < 0 { fgo = 0 }
144 if h >= 0 {
145 let tl: i64 = us_name_at(fbuf, tot, h + UR_NEEDLE_LEN, tok, US_NAMECAP)
146 if tl > 0 {
147 let ix: i64 = us_tbl_find(names, UR_STRIDE, nart, tok)
148 if ix >= 0 {
149 // count each SOURCE once per artifact: a file that names the same artifact
150 // five times is one namer, and counting mentions would flatter every row.
151 if lastsrc[ix] != si { refs[ix] = refs[ix] + 1; lastsrc[ix] = si }
152 }
153 }
154 at = h + UR_NEEDLE_LEN
155 }
156 }
157 sys_munmap(fb, tot + 16)
158 }
159 sys_munmap(flen as *u8, 64)
160 si = si + 1
161 }
162
163 // ---- 3. classify, print the worklist, reconcile the partition ----
164 var c_none: i64 = 0
165 var c_single: i64 = 0
166 var c_several: i64 = 0
167 var c_shard: i64 = 0
168 var c_self: i64 = 0
169 ur_puts("=== NX-UNREAD-SENSOR: status artifacts nothing else names ===\n" as *u8)
170 var ai: i64 = 0
171 while ai < nart {
172 let nm: *u8 = ((names as i64) + ai * UR_STRIDE) as *u8
173 var cls: i64 = us_classify(nm, refs[ai])
174 if us_is_self(nm, UR_BASELINE_NAME) == 1 { cls = US_CLASS_SEVERAL; c_self = 1 }
175 if cls == US_CLASS_NONE { c_none = c_none + 1 }
176 if cls == US_CLASS_SINGLE { c_single = c_single + 1 }
177 if cls == US_CLASS_SEVERAL { c_several = c_several + 1 }
178 if cls == US_CLASS_SHARD { c_shard = c_shard + 1 }
179 if cls != US_CLASS_SEVERAL { if cls != US_CLASS_SHARD {
180 ur_puts(" " as *u8); ur_puts(us_class_name(cls))
181 ur_puts(" namers=" as *u8); ur_num(refs[ai])
182 ur_puts(" " as *u8); ur_puts(nm)
183 ur_puts("\n" as *u8)
184 } }
185 ai = ai + 1
186 }
187 let csum: i64 = c_none + c_single + c_several + c_shard
188 ur_puts("artifacts=" as *u8); ur_num(nart)
189 ur_puts(" no_literal_reference=" as *u8); ur_num(c_none)
190 ur_puts(" single_namer=" as *u8); ur_num(c_single)
191 ur_puts(" named_by_several=" as *u8); ur_num(c_several)
192 ur_puts(" store_family=" as *u8); ur_num(c_shard)
193 ur_puts(" self_bookkeeping_excluded=" as *u8); ur_num(c_self)
194 ur_puts(" sum=" as *u8); ur_num(csum)
195 ur_puts("\n" as *u8)
196 ur_puts("corpus_declared=" as *u8); ur_num(ncorp)
197 ur_puts(" scanned=" as *u8); ur_num(scanned)
198 ur_puts(" unreadable=" as *u8); ur_num(unreadable)
199 ur_puts(" truncated_at_cap=" as *u8); ur_num(truncated)
200 ur_puts(" corpus_complete=" as *u8)
201 var complete: i64 = 1
202 if unreadable > 0 { complete = 0 }
203 if art_full == 1 { complete = 0 }
204 if scanned != got { complete = 0 }
205 ur_num(complete)
206 ur_puts("\n" as *u8)
207 if art_full == 1 { ur_puts("ARTIFACT-TABLE-FULL the counts above are a FLOOR, not a total\n" as *u8) }
208 if complete == 0 { ur_puts("COVERAGE-PARTIAL at least one source was unreadable or read only to its cap, so a NO-LITERAL-REFERENCE row is UNPROVEN rather than absent\n" as *u8) }
209
210 // ---- 4. the ratchet ----
211 let bb: *u8 = sys_mmap(64)
212 let bfd: i64 = sys_openat_rd(UR_BASELINE)
213 var base: i64 = 0 - 1
214 if bfd >= 0 {
215 let bn: i64 = sys_read(bfd, bb, 63)
216 sys_close(bfd)
217 if bn > 0 {
218 bb[bn] = 0 as u8
219 var v: i64 = 0
220 var bi: i64 = 0
221 var any: i64 = 0
222 while bi < bn {
223 let c: i64 = bb[bi] as i64
224 if c >= US_D0 { if c <= US_D9 { v = v * 10 + (c - US_D0); any = 1 } }
225 bi = bi + 1
226 }
227 if any == 1 { base = v }
228 }
229 }
230 var rc: i64 = UR_EXIT_GREEN
231 // A ratchet may only be rewritten on a FALL or on a first sight. Rewriting it on a RISE is how a
232 // detector launders itself green, and it is the one mutation that makes the whole thing decorative.
233 var write_base: i64 = 0
234 if base < 0 { write_base = 1 }
235 if base >= 0 { if c_single < base { write_base = 1 } }
236 if base >= 0 { if c_single > base { rc = UR_EXIT_RED } }
237 if complete == 0 { rc = UR_EXIT_UNPROVEN }
238 if write_base == 1 {
239 let wfd: i64 = sys_openat_wr(UR_BASELINE, UR_MODE_644)
240 if wfd >= 0 {
241 let ob: *u8 = sys_mmap(64)
242 var oo: i64 = gk_catn(ob, 0, c_single)
243 ob[oo] = 10 as u8
244 sys_write(wfd, ob, oo + 1)
245 sys_close(wfd)
246 }
247 }
248 ur_puts("ratchet baseline=" as *u8); ur_num(base)
249 ur_puts(" current=" as *u8); ur_num(c_single)
250 ur_puts(" rewritten=" as *u8); ur_num(write_base)
251 ur_puts("\n" as *u8)
252 if rc == UR_EXIT_GREEN { ur_puts("verdict=GREEN\n" as *u8) }
253 if rc == UR_EXIT_RED { ur_puts("verdict=RED the single-namer count ROSE above its baseline -- a new sensor was shipped with nothing reading it\n" as *u8) }
254 if rc == UR_EXIT_UNPROVEN { ur_puts("verdict=UNPROVEN coverage was partial, so the count is a floor and the ratchet is not judged\n" as *u8) }
255 return rc
256}