nx_sweepgate.nx source
↩ module page · 431 lines · 23063 B
1// nx_sweepgate.nx -- ASK A POPULATION QUESTION BY ITS INVARIANT, AND SEE EVERY SPELLING OF IT.
2//
3// WHY THIS EXISTS, from a measured failure on 2026-08-14. An out-of-bounds allocation bug was swept for
4// with the pattern `sys_mmap(128) as *NxEGraph`. That returned 9 sites in 5 files, and the number was
5// published as the population. It was the population OF ONE SPELLING: the same struct was also being
6// allocated at 256 and at 96, and the 96-byte sites overran a 280-byte struct by 184 bytes -- the WORST
7// sites in the estate, left live by a sweep that reported a clean, confident, complete-looking answer.
8// The true population was 27 sites in 16 files. What eventually surfaced the miss was not another grep;
9// it was the arena's ring detector printing ARENA-OVERRUN while the gate reported 15/15 GREEN.
10//
11// -- A SWEEP THAT MATCHES THE WRONG VALUE REPORTS A CLEAN POPULATION AND LEAVES THE WORST SITES LIVE.
12//
13// THE RULE THIS MAKES MECHANICAL: query by the INVARIANT (`as *NxEGraph`), never by an INSTANCE
14// (`sys_mmap(128) as *NxEGraph`). An instance pattern cannot answer a question about its own siblings,
15// and it fails in the direction of looking finished. So this organ takes the invariant, finds every
16// line, and reports the DISTINCT NUMERIC LITERALS across those lines with their counts. On the real
17// case its first line of output would have been:
18// shapes=3 128 x9 256 x11 96 x6
19// and the 17 hidden sites are visible before anyone acts on the 9.
20//
21// IT ALSO REFUSES TO CENSUS THROUGH A PARTIAL SCAN. nx_shelltool already prints coverage_complete and
22// corpus_complete; on 2026-08-14 a `matches=0` was read as absence while corpus_complete was 0, and the
23// wrong conclusion was published. Those flags are fields a reader may ignore, so this organ reads them
24// FOR the reader and returns UNPROVEN rather than a number it cannot stand behind.
25// -- A NUMBER THAT MIGHT BE PARTIAL IS MORE DANGEROUS THAN NO NUMBER.
26//
27// COMPOSES nx_shelltool; adds no second scanner. exit 0 SINGLE-SHAPE - 1 SPLIT (the finding) -
28// 3 UNPROVEN (partial coverage, or the tool could not be reached) - 2 usage.
29// license_tier: ORIGINAL expect_exit: 0
30
31import "nx_tool_run.nx"
32
33const SG_MAX_SHAPES: i64 = 64
34const SG_CAP: i64 = 1048576
35const SG_COLON: i64 = 58
36const SG_NL: i64 = 10
37const SG_D0: i64 = 48
38const SG_D9: i64 = 57
39
40func 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 }
41func sg_n(v: i64) -> i64 {
42 var m: i64 = v; if m < 0 { sg_w("-" as *u8); m = 0 - m }
43 let t: *u8 = sys_mmap(24); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
44 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
45 let o: *u8 = sys_mmap(24); var i: i64 = 0; while i < k { o[i] = t[k-1-i]; i = i + 1 } sys_write(1, o, k); return 0
46}
47// Is `needle` present in buf[0..n)? Composes the incumbent rather than adding a matcher.
48func sg_has(buf: *u8, n: i64, needle: *u8) -> i64 { return tr_contains(buf, n, needle) }
49
50// THE LOAD-BEARING LOGIC, EXTRACTED SO IT CAN BE PROVEN. Tally distinct integer literals across the
51// CONTENT of each `path:lineno:content` row. The prefix is skipped deliberately -- a path can carry
52// digits (nx_p256) and a line number always does, and counting either would drown the signal in noise.
53// Returns the number of distinct shapes, or 0-1 if the shape table overflowed.
54func sg_tally(buf: *u8, n: i64, vals: *i64, cnts: *i64, lines_out: *i64) -> i64 {
55 var nshapes: i64 = 0
56 var lines: i64 = 0
57 var p: i64 = 0
58 while p < n {
59 var e: i64 = p
60 while e < n { if buf[e] == (SG_NL as u8) { break } e = e + 1 }
61 var colons: i64 = 0
62 var c: i64 = p
63 var content: i64 = 0 - 1
64 while c < e {
65 if buf[c] == (SG_COLON as u8) {
66 colons = colons + 1
67 if colons == 2 { content = c + 1; c = e }
68 }
69 c = c + 1
70 }
71 if content > 0 {
72 lines = lines + 1
73 // COMMENT PROSE IS NOT CODE. Truncate the content at `//`. Caught by running the real census:
74 // the first live run tallied 128 x3 entirely from a COMMENT that describes this very bug --
75 // the prose-is-source-bytes trap, biting the detector built to find it.
76 var stop_at: i64 = e
77 var sc: i64 = content
78 while sc < e - 1 {
79 if buf[sc] == (47 as u8) { if buf[sc+1] == (47 as u8) { stop_at = sc; sc = e } }
80 sc = sc + 1
81 }
82 var i: i64 = content
83 while i < stop_at {
84 let ch: i64 = buf[i] as i64
85 if ch >= SG_D0 { if ch <= SG_D9 {
86 // A DIGIT RUN GLUED TO AN IDENTIFIER IS PART OF THE NAME, NOT A VALUE. Caught by the
87 // first live census, which reported 2 x4 / 3 x3 / 5 x3 -- every one of them the tail
88 // of a local called eg2, g3 or c8. Counting those drowns the real spellings in noise,
89 // and a detector with false positives is worse than none because everyone learns to
90 // ignore it.
91 var glued: i64 = 0
92 if i > content {
93 let pv: i64 = buf[i-1] as i64
94 if pv == 95 { glued = 1 }
95 if pv >= 65 { if pv <= 90 { glued = 1 } }
96 if pv >= 97 { if pv <= 122 { glued = 1 } }
97 }
98 var v: i64 = 0
99 var stop: i64 = 0
100 while stop == 0 {
101 if i >= stop_at { stop = 1 } else {
102 let d: i64 = buf[i] as i64
103 if d < SG_D0 { stop = 1 } else { if d > SG_D9 { stop = 1 } else {
104 v = v * 10 + (d - SG_D0); i = i + 1
105 } }
106 }
107 }
108 if glued == 0 {
109 var k: i64 = 0
110 var seen: i64 = 0
111 while k < nshapes { if vals[k] == v { cnts[k] = cnts[k] + 1; seen = 1; k = nshapes } else { k = k + 1 } }
112 if seen == 0 {
113 if nshapes < SG_MAX_SHAPES { vals[nshapes] = v; cnts[nshapes] = 1; nshapes = nshapes + 1 }
114 else { lines_out[0] = lines; return 0 - 1 }
115 }
116 }
117 } }
118 i = i + 1
119 }
120 }
121 p = e + 1
122 }
123 lines_out[0] = lines
124 return nshapes
125}
126
127// SELFTEST -- runs when invoked with NO arguments, which is how /api/gate_run invokes a verifier.
128// This is a self-test, NOT a silent default doing real work: it cannot emit a population claim about
129// the estate, so it carries none of the risk that made the stale-default challenger a false-verdict
130// generator. It proves the tally on a crafted buffer whose right answer is known by construction.
131func sg_selftest() -> i64 {
132 sg_w("nx_sweepgate selftest -- the shape tally, on a buffer whose answer is known by construction\n\n" as *u8)
133 let vals: *i64 = sys_mmap(SG_MAX_SHAPES * 8) as *i64
134 let cnts: *i64 = sys_mmap(SG_MAX_SHAPES * 8) as *i64
135 let lo: *i64 = sys_mmap(16) as *i64
136 // THE EXACT SHAPE OF THE REAL FAILURE: one invariant, three spellings, plus digits in the PATH
137 // (nx_p256) and in every line number -- all of which must be ignored or the signal drowns.
138 // FIXTURE WIDENED 2026-08-14 AFTER THE FIRST LIVE RUN EXPOSED IT AS TOO NARROW. The original held
139 // only clean `sys_mmap(N)` rows, so it could not fail on either defect the real census immediately
140 // hit: digits welded to an identifier (eg2, g3, c8) and digits inside COMMENT prose. It passed 6/6
141 // while the shipped organ produced 6 shapes on real data, 5 of them noise.
142 // -- A FIXTURE THE DEFECT CANNOT FAIL IS NOT A TEST.
143 let fix: *u8 = "a/nx_p256.nx:99:let g = sys_mmap(128) as *Foo\nb/x.nx:12:let g = sys_mmap(256) as *Foo\nc/y.nx:7:let g = sys_mmap(128) as *Foo\nd/z.nx:1:let g = sys_mmap(96) as *Foo\ne/w.nx:3:let eg2 = sys_mmap(128) as *Foo\nf/v.nx:8:// sys_mmap(999) as *Foo -- prose about the bug\n-- matches=6 coverage_complete=1 corpus_complete=1\n" as *u8
144 var fn: i64 = 0
145 while fix[fn] != (0 as u8) { fn = fn + 1 }
146 let ns: i64 = sg_tally(fix, fn, vals, cnts, lo)
147
148 var pass: i64 = 0
149 var total: i64 = 0
150 // three distinct spellings found
151 total = total + 1; if ns == 3 { pass = pass + 1; sg_w(" three distinct spellings detected: PASS\n" as *u8) } else { sg_w(" three distinct spellings detected: FAIL\n" as *u8) }
152 // the repeated one is counted twice, the others once
153 var c128: i64 = 0
154 var c256: i64 = 0
155 var c96: i64 = 0
156 var k: i64 = 0
157 while k < ns {
158 if vals[k] == 128 { c128 = cnts[k] }
159 if vals[k] == 256 { c256 = cnts[k] }
160 if vals[k] == 96 { c96 = cnts[k] }
161 k = k + 1
162 }
163 total = total + 1; if c128 == 3 { pass = pass + 1; sg_w(" the repeated spelling is counted three times: PASS\n" as *u8) } else { sg_w(" the repeated spelling is counted three times: FAIL\n" as *u8) }
164 total = total + 1; if c256 == 1 { pass = pass + 1; sg_w(" the second spelling is counted once: PASS\n" as *u8) } else { sg_w(" the second spelling is counted once: FAIL\n" as *u8) }
165 total = total + 1; if c96 == 1 { pass = pass + 1; sg_w(" the third and worst spelling is counted once: PASS\n" as *u8) } else { sg_w(" the third and worst spelling is counted once: FAIL\n" as *u8) }
166 // NEG-CONTROL: the digits in the PATH (256 in nx_p256) and the LINE NUMBERS (99, 12, 7, 1) must NOT
167 // become shapes. Without this the tally would look right while counting noise -- and 256 appears in
168 // BOTH a path and a real value here on purpose, so a prefix-skipping bug cannot hide behind it.
169 total = total + 1; if ns == 3 { pass = pass + 1; sg_w(" neg-control-path-and-line-number-digits-are-NOT-counted-as-shapes: PASS\n" as *u8) } else { sg_w(" neg-control-path-and-line-number-digits-are-NOT-counted-as-shapes: FAIL\n" as *u8) }
170 // NEG-CONTROL: the summary row has no second colon, so it must contribute no line and no shape.
171 total = total + 1; if lo[0] == 6 { pass = pass + 1; sg_w(" neg-control-the-scanner-summary-row-is-not-mistaken-for-a-match: PASS\n" as *u8) } else { sg_w(" neg-control-the-scanner-summary-row-is-not-mistaken-for-a-match: FAIL\n" as *u8) }
172 // THE TWO CONTROLS THE ORIGINAL FIXTURE LACKED, each one a defect the live census actually hit.
173 var saw2: i64 = 0
174 var saw999: i64 = 0
175 var kk: i64 = 0
176 while kk < ns { if vals[kk] == 2 { saw2 = 1 } if vals[kk] == 999 { saw999 = 1 } kk = kk + 1 }
177 total = total + 1; if saw2 == 0 { pass = pass + 1; sg_w(" neg-control-digits-welded-to-an-identifier-are-NOT-a-value: PASS\n" as *u8) } else { sg_w(" neg-control-digits-welded-to-an-identifier-are-NOT-a-value: FAIL\n" as *u8) }
178 total = total + 1; if saw999 == 0 { pass = pass + 1; sg_w(" neg-control-a-number-in-COMMENT-prose-is-NOT-a-value: PASS\n" as *u8) } else { sg_w(" neg-control-a-number-in-COMMENT-prose-is-NOT-a-value: FAIL\n" as *u8) }
179
180 sg_w("\nNX-nx_sweepgate passed " as *u8); sg_n(pass); sg_w("/" as *u8); sg_n(total)
181 if pass == total { sg_w(" verdict=GREEN (shape tally proven on the exact shape of the real failure)\n" as *u8); return 0 }
182 sg_w(" verdict=RED\n" as *u8)
183 return 1
184}
185
186// ONE CENSUS PATH, called by BOTH the argv route and the conf-driven watch route. Returns
187// 0 SINGLE-SHAPE - 1 SPLIT - 3 UNPROVEN. It never exits, so a watch sweep can run every row and report
188// them all rather than stopping at the first finding.
189func sg_census(inv: *u8, dir: *u8, ext: *u8) -> i64 {
190 let out: *u8 = sys_mmap(SG_CAP)
191 let ol: *i64 = sys_mmap(16) as *i64
192 let av: *i64 = sys_mmap(64) as *i64
193
194 // CWD PROBE, not an assumption: a gate may run from the nishihost root or from buildroot, and a
195 // tool path that resolves in one and not the other is the difference between a census and a lie.
196 var tool: *u8 = "nx_shelltool.elf" as *u8
197 var fd: i64 = sys_openat_rd(tool)
198 if fd < 0 {
199 tool = "../nx_shelltool.elf" as *u8
200 fd = sys_openat_rd(tool)
201 if fd < 0 {
202 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=scanner-unreachable\n" as *u8)
203 sg_w(" nx_shelltool.elf resolves from neither the serving root nor buildroot; I could not look.\n" as *u8)
204 return 3
205 }
206 }
207 sys_close(fd)
208
209 av[0] = tool as i64
210 av[1] = "grep" as i64
211 av[2] = inv as i64
212 av[3] = dir as i64
213 var an: i64 = 4
214 if (ext as i64) != 0 { av[an] = ext as i64; an = an + 1 }
215 av[an] = 0
216 let rc: i64 = tr_run_capture(tool, av, out, SG_CAP, ol)
217 let n: i64 = ol[0]
218 if rc != 0 {
219 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=scanner-failed rc=" as *u8); sg_n(rc); sg_w("\n" as *u8)
220 return 3
221 }
222
223 // THE ONE BOUND IN THIS ORGAN ANSWERS FOR ITSELF. SG_CAP exists because a subprocess's output
224 // length is genuinely unknowable before it runs -- that is the only kind of ceiling this estate
225 // permits, and the rule that permits it also requires the truncation to ANNOUNCE.
226 // The envelope check below would catch this today too, because the scanner prints its coverage
227 // line LAST and a truncated capture loses it. But that is an accident of ordering, not a
228 // guarantee: let the scanner ever print its envelope first and that protection disappears without
229 // one test failing anywhere. A guard that works only because of where somebody else puts a line is
230 // not a guard. So the cap refuses in its own name, and says how many bytes it took.
231 if n >= SG_CAP {
232 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=capture-cap-reached bytes=" as *u8); sg_n(n)
233 sg_w(" -- the scan may have been complete; THIS ORGAN's read of it was not, and those are different failures\n" as *u8)
234 return 3
235 }
236
237 // READ THE ENVELOPE BEFORE THE NUMBERS. A census through a partial scan is worse than none.
238 if sg_has(out, n, "coverage_complete=1" as *u8) != 1 {
239 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=coverage-incomplete\n" as *u8)
240 sg_w(" the scanner did not cover everything it was pointed at, so no population claim is available.\n" as *u8)
241 return 3
242 }
243 if sg_has(out, n, "corpus_complete=1" as *u8) != 1 {
244 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=corpus-incomplete\n" as *u8)
245 sg_w(" the scan hit a budget or a cap. matches=0 from here is NOT absence, in either direction.\n" as *u8)
246 return 3
247 }
248
249 // ONE TALLY, NOT TWO. The census and the selftest call the SAME function, so the thing the selftest
250 // proves is the thing the census runs -- a second copy here would be the duplicate-ruler defect and
251 // the proof would drift away from the shipped path without anyone noticing.
252 let vals: *i64 = sys_mmap(SG_MAX_SHAPES * 8) as *i64
253 let cnts: *i64 = sys_mmap(SG_MAX_SHAPES * 8) as *i64
254 let lo: *i64 = sys_mmap(16) as *i64
255 let nshapes: i64 = sg_tally(out, n, vals, cnts, lo)
256 let lines: i64 = lo[0]
257 var overflow: i64 = 0
258 if nshapes < 0 { overflow = 1 }
259
260 sg_w("NX-SWEEPGATE invariant=" as *u8); sg_w(inv)
261 sg_w(" dir=" as *u8); sg_w(dir)
262 sg_w(" lines=" as *u8); sg_n(lines)
263 sg_w(" shapes=" as *u8); sg_n(nshapes); sg_w("\n" as *u8)
264 var k2: i64 = 0
265 while k2 < nshapes {
266 sg_w(" " as *u8); sg_n(vals[k2]); sg_w(" x" as *u8); sg_n(cnts[k2]); sg_w("\n" as *u8)
267 k2 = k2 + 1
268 }
269 // A CAP REACHED IN SILENCE BECOMES A MEASUREMENT NOBODY KNOWS IS PARTIAL.
270 if overflow == 1 {
271 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=shape-table-full -- more distinct literals than this organ can hold\n" as *u8)
272 return 3
273 }
274 if lines == 0 {
275 sg_w("NX-SWEEPGATE verdict=UNPROVEN reason=no-matching-lines -- nothing to census (the scan WAS complete)\n" as *u8)
276 return 3
277 }
278 if nshapes > 1 {
279 sg_w("NX-SWEEPGATE verdict=SPLIT -- this population is written more than one way, so a sweep for any ONE of the values above would have reported a clean and incomplete answer\n" as *u8)
280 return 1
281 }
282 sg_w("NX-SWEEPGATE verdict=SINGLE-SHAPE -- one spelling across the whole matched population\n" as *u8)
283 return 0
284}
285
286// ---- THE DURABLE RECORD ----
287// A beat whose output goes nowhere is a beat nobody can audit: the estate pays for the run and
288// collects nothing, which is the same failure as not running at all. One line per run, appended, so
289// "when did this population split?" has an answer with a date on it instead of whatever the last
290// person happened to still have on their terminal.
291// ONE WRITER, ONE FILE -- a log several organs append to measures a race, not a subject.
292// The canonical verdict field goes LAST on the line, because a positional reader takes the answer and
293// can never pick up a field name that happens to appear in the prose beside it.
294// UNPROVEN is emitted as itself, never folded into RED or GREEN: an axis that could not look must
295// abstain, and collapsing "I could not see" into either answer is a lie in one direction or the other.
296func sg_dig(b: *u8, o: i64, v: i64, tmp: *u8) -> i64 {
297 if v == 0 { b[o] = SG_D0 as u8; return o + 1 }
298 var k: i64 = 0
299 var x: i64 = v
300 while x > 0 { tmp[k] = (SG_D0 + (x % 10)) as u8; x = x / 10; k = k + 1 }
301 var oo: i64 = o
302 while k > 0 { k = k - 1; b[oo] = tmp[k]; oo = oo + 1 }
303 return oo
304}
305
306func sg_put(b: *u8, o: i64, s: *u8) -> i64 {
307 var i: i64 = 0
308 var oo: i64 = o
309 while s[i] != (0 as u8) { b[oo] = s[i]; i = i + 1; oo = oo + 1 }
310 return oo
311}
312
313func sg_log(rows: i64, splits: i64, unproven: i64, verdict: *u8) -> i64 {
314 let b: *u8 = sys_mmap(512)
315 let tmp: *u8 = sys_mmap(64)
316 var o: i64 = 0
317 o = sg_put(b, o, "NX-SWEEPGATE watch rows=" as *u8)
318 o = sg_dig(b, o, rows, tmp)
319 o = sg_put(b, o, " split=" as *u8)
320 o = sg_dig(b, o, splits, tmp)
321 o = sg_put(b, o, " unproven=" as *u8)
322 o = sg_dig(b, o, unproven, tmp)
323 o = sg_put(b, o, " verdict=" as *u8)
324 o = sg_put(b, o, verdict)
325 b[o] = SG_NL as u8
326 o = o + 1
327 let fd: i64 = sys_openat_append("knowledge/status/sweepgate.log" as *u8, MODE_0644)
328 if fd < 0 {
329 sg_w("NX-SWEEPGATE log=UNWRITTEN -- the durable record could not be opened, so this run leaves nothing behind it\n" as *u8)
330 return 1
331 }
332 let w: i64 = sys_write(fd, b, o)
333 sys_close(fd)
334 // ANNOUNCE. A feature that prints nothing when it works is indistinguishable from one that was
335 // never compiled in -- absent code has no failure mode, so the build stays clean and the run stays
336 // green while the record silently stops being written. Publishing the byte counts turns "did the
337 // log land?" into one number the reader already has, instead of a hunt through the filesystem.
338 sg_w("NX-SWEEPGATE log=knowledge/status/sweepgate.log wrote=" as *u8); sg_n(w)
339 sg_w(" of=" as *u8); sg_n(o); sg_w("\n" as *u8)
340 return 0
341}
342
343// THE STANDING CENSUS. Rows live in a conf, so the estate declares WHAT must stay single-spelled and
344// this organ checks it on every beat. That is the difference between a tool somebody could run and a
345// control that actually runs -- the gap this whole session was spent closing.
346// Running declared conf rows on no-argv is NOT the silent-default defect: the rows are explicit, they
347// are in the SSOT, and a missing conf is reported as UNOBSERVABLE rather than treated as clean.
348func sg_watch() -> i64 {
349 let cl: *i64 = sys_mmap(16) as *i64
350 var conf: *u8 = sys_read_file("knowledge/status/sweepgate_watch.conf" as *u8, cl)
351 if (conf as i64) == 0 { conf = sys_read_file("buildroot/knowledge/status/sweepgate_watch.conf" as *u8, cl) }
352 if (conf as i64) == 0 {
353 sg_w("\nNX-SWEEPGATE watch=UNOBSERVABLE -- sweepgate_watch.conf resolves from neither root; declared rows unknown\n" as *u8)
354 return 3
355 }
356 let n: i64 = cl[0]
357 sg_w("\nstanding census over the declared watch rows:\n" as *u8)
358 var rows: i64 = 0
359 var splits: i64 = 0
360 var unproven: i64 = 0
361 var p: i64 = 0
362 while p < n {
363 var e: i64 = p
364 while e < n { if conf[e] == (SG_NL as u8) { break } e = e + 1 }
365 if e > p { if conf[p] != (35 as u8) {
366 // split on '|' in place: invariant | dir | ext
367 var f1: i64 = 0 - 1
368 var f2: i64 = 0 - 1
369 var c: i64 = p
370 while c < e {
371 if conf[c] == (124 as u8) { if f1 < 0 { f1 = c } else { if f2 < 0 { f2 = c } } }
372 c = c + 1
373 }
374 if f1 > 0 {
375 conf[f1] = 0 as u8
376 var ext2: *u8 = 0 as *u8
377 if f2 > 0 { conf[f2] = 0 as u8; ext2 = (conf as i64 + f2 + 1) as *u8 }
378 conf[e] = 0 as u8
379 let inv2: *u8 = (conf as i64 + p) as *u8
380 let dir2: *u8 = (conf as i64 + f1 + 1) as *u8
381 rows = rows + 1
382 let rv: i64 = sg_census(inv2, dir2, ext2)
383 if rv == 1 { splits = splits + 1 }
384 if rv == 3 { unproven = unproven + 1 }
385 }
386 } }
387 p = e + 1
388 }
389 sg_w("\nwatch rows=" as *u8); sg_n(rows)
390 sg_w(" split=" as *u8); sg_n(splits)
391 sg_w(" unproven=" as *u8); sg_n(unproven); sg_w("\n" as *u8)
392 if rows == 0 {
393 sg_w("NX-SWEEPGATE watch=UNOBSERVABLE -- the conf declared no rows\n" as *u8)
394 sg_log(rows, splits, unproven, "UNPROVEN" as *u8)
395 return 3
396 }
397 if unproven > 0 {
398 sg_w("NX-SWEEPGATE watch=UNPROVEN -- at least one row could not be censused\n" as *u8)
399 sg_log(rows, splits, unproven, "UNPROVEN" as *u8)
400 return 3
401 }
402 if splits > 0 {
403 sg_w("NX-SWEEPGATE watch=SPLIT -- a declared population is written more than one way\n" as *u8)
404 sg_log(rows, splits, unproven, "RED" as *u8)
405 return 1
406 }
407 sg_w("NX-SWEEPGATE watch=CLEAN -- every declared population has exactly one spelling\n" as *u8)
408 sg_log(rows, splits, unproven, "GREEN" as *u8)
409 return 0
410}
411
412func main(argc: i64, argv: *i64) -> i64 {
413 if argc < 2 {
414 let rc0: i64 = sg_selftest()
415 let rc1: i64 = sg_watch()
416 var rc: i64 = rc0
417 if rc1 != 0 { rc = rc1 }
418 sys_exit(rc); return rc
419 }
420 if argc < 3 {
421 sg_w("usage: nx_sweepgate <invariant> <dir> [ext]\n" as *u8)
422 sg_w(" Query by the INVARIANT the sites share, never by one instance of it. Reports every\n" as *u8)
423 sg_w(" distinct numeric literal across the matching lines, so a second spelling cannot hide.\n" as *u8)
424 sg_w(" With NO arguments it runs its selftest AND the declared watch rows.\n" as *u8)
425 sys_exit(2); return 2
426 }
427 var ext3: *u8 = 0 as *u8
428 if argc >= 4 { ext3 = argv[3] as *u8 }
429 let rc2: i64 = sg_census(argv[1] as *u8, argv[2] as *u8, ext3)
430 sys_exit(rc2); return rc2
431}