nx_planepeek.nx source
↩ module page · 393 lines · 19208 B
1// nx_planepeek.nx -- READ ONE RAW KEY OUT OF A SEG-STORE PLANE. Read-only, writes nothing.
2//
3// WHY IT EXISTS. The debt- plane is refusing every add/eat because ONE row is reachable past the
4// declared q:n (nx_plane_check: rows=3696 identical=3696 declared_qn=3696 beyond_qn=1), and
5// nx_plane_repair correctly refuses to reconcile it: "an older seeding generation -- reseeding would
6// revive eaten rows and duplicate live ones. That needs a generation diff, not a reconcile."
7// To DO that generation diff somebody has to look at the row. And nothing in the estate could:
8// nx_store_put reads its own N-column planes, nx_plane_check verifies round-trips, nx_store_hist is a
9// column histogram -- none of them will hand you the value at an arbitrary key.
10// ★★★★★A PLANE YOU CAN VERIFY AND REPAIR BUT CANNOT READ A SINGLE KEY OUT OF FORCES EVERY DIAGNOSIS
11// TO BE A GUESS. I made two wrong guesses about this exact row before building this.
12//
13// It is deliberately the smallest thing that closes that gap: resolve a key through the SAME
14// production ss_get every reader uses, print the bytes, exit. No writes, no repair, no opinion.
15//
16// ===========================================================================================
17// THE FALSE-ABSENCE DEFECT (debt 1787282525, sev 6, fixed 2026-08-21).
18// ===========================================================================================
19// v1 printed exactly one word for every non-hit: `if ss_get(...) != 1 { MISS }`.
20// ss_get's OWN contract (nx_seg_store.nx: "1=found, 0=tombstoned, -1=absent") already carried a
21// state v1 threw away, and the scan underneath it carried three more:
22// 1. ss_get==0 -> the key EXISTS and was explicitly DELETED. v1 said MISS. A tombstone is a
23// POSITIVE fact about a key, and reporting it as absence inverts its meaning.
24// 2. no manifest -> ss_manifest_dyn returns 0, ss_scan returns 0, ss_get returns -1. So a
25// MISTYPED PREFIX printed the same MISS as a real absence. Nothing could tell them apart.
26// 3. a segment NAMED in manifest.txt but UNREADABLE on disk -> ss_readall sets sz=-1 and
27// ss_scan_seglist's `while i + 9 <= sz` loop never executes. The segment contributes ZERO
28// rows and NO error. A plane half of which could not be opened answered a confident "absent".
29// 4. a caller passing a COLUMN VALUE where the plane's keys are q:<n> (every N-col plane written
30// by nx_store_put) got MISS, which reads as "your row is gone" rather than "wrong grammar".
31// FIVE distinguishable conditions, ONE word, and that word is a NEGATIVE ASSERTION. Measured cost:
32// a seat nearly filed "the enqueue lane is dead" on it, and a build-refusal message shipped
33// `verify with nx_planepeek deployq- BQ-<target>` -- pointing every caller at a false-absence
34// generator. ★★★★★★AN UNBOUNDED SEARCH THAT GIVES UP MUST NOT REPORT THE SAME WORD AS AN
35// EXHAUSTIVE ONE THAT FOUND NOTHING -- otherwise every quote of it silently rewrites the
36// evidential status of the claim that quotes it.
37// ⇒ MISS now means ONE thing: the plane resolved, EVERY declared segment was read, the key is not
38// there. Everything else gets its own word and its own exit code, and every answer -- hit or
39// miss -- prints the coverage it was computed from.
40// ★PRESENCE NEEDS ONE WITNESS; ABSENCE NEEDS PROVEN COVERAGE. So the HIT path stays a cheap point
41// lookup and only the NEGATIVE answer pays for the enumeration that proves it.
42//
43// usage: nx_planepeek <prefix> <key> -- print the value at that key, or MISS
44// nx_planepeek <prefix> range <a> <b> -- print q:<a> .. q:<b> (inclusive), MISS lines kept
45// exits: 0 HIT | 1 MISS (proven exhaustive) | 2 usage | 3 UNPROVEN (coverage incomplete)
46// 4 NO-SUCH-PLANE | 5 TOMBSTONED (key present, deleted) | 6 NOT-A-KEY (it is a column value)
47// ⚠`range` is bounded by PK_MAXRANGE and SAYS SO when it clamps -- a peek that silently stopped early
48// would be the same defect class this lane spent the day measuring.
49// ⚠THE ARCHIVE IS A DECLARED HORIZON, NOT A SCANNED ONE. ss_get reads manifest.txt only; compaction
50// retires segments into manifest-archive.txt (the clocksched- plane: 5 live, 460+ archived). This
51// organ PRINTS archive_segments= so the horizon is visible, and deliberately does not read them --
52// ★AN INSTRUMENT'S SAMPLING WINDOW MUST BE PUBLISHED OR IT READS AS COMPLETENESS.
53// license_tier: ORIGINAL Read-only. No hw writes (Rule 26).
54import "nx_seg_store.nx"
55import "nx_syscalls.nx"
56
57const PK_KEYCAP: i64 = 256
58const PK_MAXRANGE: i64 = 200
59const PK_ZERO: i64 = 48
60const PK_NINE: i64 = 57
61// Column separator in every N-col plane row: nx_store_put joins fields with a TAB, so column 0 of a
62// row value is the bytes up to the first TAB. That is what makes the NOT-A-KEY diagnosis DERIVED
63// from the data rather than assumed from a naming convention.
64const PK_TAB: i64 = 9
65// Path buffer width. NOT a fresh guess: this is the same 512 ss_scan_seglist and ss_cur_next use to
66// build "<prefix><seg>.docs", so the peek cannot overflow where the production scan does not.
67const PK_PATHCAP: i64 = 512
68
69// ---- EXIT CONTRACT. Every state the lookup can be in gets its own code, because a caller that
70// ---- cannot branch on the reason will branch on MISS and be wrong.
71const PK_EX_HIT: i64 = 0
72const PK_EX_MISS: i64 = 1
73const PK_EX_USAGE: i64 = 2
74const PK_EX_UNPROVEN: i64 = 3
75const PK_EX_NOPLANE: i64 = 4
76const PK_EX_TOMBSTONED: i64 = 5
77const PK_EX_NOTAKEY: i64 = 6
78
79// ss_get's return alphabet, named at the call site so the mapping is readable (nx_seg_store.nx:
80// "latest state of key: 1=found, 0=tombstoned, -1=absent").
81const PK_SS_TOMB: i64 = 0
82const PK_SS_HIT: i64 = 1
83
84// ---- COVERAGE RECORD. Filled before any verdict; printed with every verdict.
85const PK_COV_SLOTS: i64 = 8
86const PK_COV_DECLARED: i64 = 0
87const PK_COV_READABLE: i64 = 1
88const PK_COV_UNREADABLE: i64 = 2
89const PK_COV_BYTES: i64 = 3
90const PK_COV_ARCHIVE: i64 = 4
91const PK_COV_KEYS: i64 = 5
92const PK_COV_SEGS: i64 = 6
93
94func pk_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
95func pk_puts(s: *u8) -> i64 { sys_write(1, s, pk_len(s)); return 0 }
96func pk_putn(v: i64) -> i64 {
97 if v == 0 { pk_puts("0" as *u8); return 0 }
98 var x: i64 = v
99 if x < 0 { pk_puts("-" as *u8); x = 0 - x }
100 let b: *u8 = sys_mmap(32)
101 var i: i64 = 0
102 while x > 0 { b[i] = ((x % 10) + PK_ZERO) as u8; x = x / 10; i = i + 1 }
103 while i > 0 { i = i - 1; sys_write(1, ((b as i64) + i) as *u8, 1) }
104 return 0
105}
106func pk_atoi(s: *u8) -> i64 {
107 var v: i64 = 0
108 var i: i64 = 0
109 var done: i64 = 0
110 while done == 0 {
111 let c: i64 = s[i] as i64
112 if c >= PK_ZERO { if c <= PK_NINE { v = v * 10 + (c - PK_ZERO); i = i + 1 } else { done = 1 } } else { done = 1 }
113 }
114 return v
115}
116func pk_streq(a: *u8, b: *u8) -> i64 {
117 var i: i64 = 0
118 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
119 if b[i] == (0 as u8) { return 1 }
120 return 0
121}
122// build "q:<n>" exactly as sts_rowkey does
123func pk_rowkey(seq: i64, out: *u8) -> i64 {
124 out[0] = 113 as u8 // 'q'
125 out[1] = 58 as u8 // ':'
126 var o: i64 = ss_catn(out, 2, seq)
127 out[o] = 0 as u8
128 return o
129}
130
131// ---------------------------------------------------------------------------------------------
132// COVERAGE. The whole point of the fix: establish WHAT COULD BE READ before saying what is absent.
133// ---------------------------------------------------------------------------------------------
134// Size of one segment file, or -1 if it cannot be opened. Deliberately NOT ss_readall: readability
135// is the question, and reading a 1.6 GB segment to answer it would make proving absence cost more
136// than the lookup it qualifies. openat+lseek+close is the whole probe.
137func pk_segsize(prefix: *u8, segname: *u8) -> i64 {
138 let path: *u8 = sys_mmap(PK_PATHCAP)
139 var o: i64 = ss_cat(path, 0, prefix)
140 o = ss_cat(path, o, segname)
141 o = ss_cat(path, o, ".docs" as *u8)
142 path[o] = 0 as u8
143 let fd: i64 = sys_openat_rd(path)
144 if fd < 0 { sys_munmap(path, PK_PATHCAP); return 0 - 1 }
145 let sz: i64 = sys_lseek(fd, 0, 2)
146 sys_close(fd)
147 sys_munmap(path, PK_PATHCAP)
148 return sz
149}
150
151// Fill cov from the LIVE manifest, and count (never read) the archive so the horizon is declared.
152// Returns the number of segments the live manifest declares.
153func pk_coverage(prefix: *u8, cov: *i64) -> i64 {
154 var i: i64 = 0
155 while i < PK_COV_SLOTS { cov[i] = 0; i = i + 1 }
156 let sp: *i64 = sys_mmap(16) as *i64
157 let ns: i64 = ss_manifest_dyn(prefix, sp)
158 let segs: *i64 = sp[0] as *i64
159 cov[PK_COV_DECLARED] = ns
160 cov[PK_COV_SEGS] = segs as i64
161 var s: i64 = 0
162 while s < ns {
163 let sz: i64 = pk_segsize(prefix, segs[s] as *u8)
164 if sz < 0 {
165 cov[PK_COV_UNREADABLE] = cov[PK_COV_UNREADABLE] + 1
166 } else {
167 cov[PK_COV_READABLE] = cov[PK_COV_READABLE] + 1
168 cov[PK_COV_BYTES] = cov[PK_COV_BYTES] + sz
169 }
170 s = s + 1
171 }
172 let ap: *i64 = sys_mmap(16) as *i64
173 cov[PK_COV_ARCHIVE] = ss_manifest_file_dyn(prefix, "manifest-archive.txt" as *u8, ap)
174 return ns
175}
176
177// A COUNT WITHOUT A WORKLIST IS NOT ACTIONABLE: name every segment that could not be opened.
178func pk_name_unreadable(prefix: *u8, cov: *i64) -> i64 {
179 let segs: *i64 = cov[PK_COV_SEGS] as *i64
180 let ns: i64 = cov[PK_COV_DECLARED]
181 var s: i64 = 0
182 while s < ns {
183 if pk_segsize(prefix, segs[s] as *u8) < 0 {
184 pk_puts(" UNREADABLE-SEGMENT " as *u8)
185 pk_puts(segs[s] as *u8)
186 pk_puts(".docs\n" as *u8)
187 }
188 s = s + 1
189 }
190 return 0
191}
192
193// The coverage line every verdict carries. A PARTITION IS A CLAIM: declared == readable+unreadable,
194// and the sum is PRINTED so a reader can check it rather than trust it.
195func pk_put_coverage(cov: *i64) -> i64 {
196 pk_puts("COVERAGE segments_declared=" as *u8); pk_putn(cov[PK_COV_DECLARED])
197 pk_puts(" read=" as *u8); pk_putn(cov[PK_COV_READABLE])
198 pk_puts(" unreadable=" as *u8); pk_putn(cov[PK_COV_UNREADABLE])
199 pk_puts(" sum=" as *u8); pk_putn(cov[PK_COV_READABLE] + cov[PK_COV_UNREADABLE])
200 pk_puts(" bytes=" as *u8); pk_putn(cov[PK_COV_BYTES])
201 pk_puts(" keys_scanned=" as *u8); pk_putn(cov[PK_COV_KEYS])
202 pk_puts(" archive_segments=" as *u8); pk_putn(cov[PK_COV_ARCHIVE])
203 pk_puts(" (archive NOT scanned -- declared horizon)\n" as *u8)
204 return 0
205}
206
207// ---------------------------------------------------------------------------------------------
208// THE ABSENCE PROOF. Only ever runs when ss_get already said "not here", so the hit path is
209// untouched. Composes the incumbent enumerator ss_cur_next rather than adding a THIRD copy of the
210// record-framing walk (ss_scan_seglist and ss_cur_next already carry one each).
211// Returns 1 if `key` was found as COLUMN 0 of some row (=> NOT-A-KEY), 0 otherwise.
212// Writes the real key of that row into realkey/realkeylen when it returns 1, and counts every key
213// it walked into cov[PK_COV_KEYS] -- that count IS the evidence the scan was exhaustive.
214func pk_scan_for_colvalue(prefix: *u8, key: *u8, cov: *i64, rk: *i64, rkl: *i64) -> i64 {
215 let kl0: i64 = pk_len(key)
216 let st: *i64 = ss_cur_open(prefix)
217 let kp: *i64 = sys_mmap(16) as *i64
218 let klp: *i64 = sys_mmap(16) as *i64
219 let vp: *i64 = sys_mmap(16) as *i64
220 let vlp: *i64 = sys_mmap(16) as *i64
221 var found: i64 = 0
222 var more: i64 = 1
223 while more == 1 {
224 if ss_cur_next(prefix, st, kp, klp, vp, vlp) != 1 {
225 more = 0
226 } else {
227 cov[PK_COV_KEYS] = cov[PK_COV_KEYS] + 1
228 if found == 0 {
229 // column 0 = value bytes up to the first TAB (or the whole value if none).
230 // Separate cursor and flag: a loop that exits by clobbering its own cursor cannot
231 // also report where it stopped.
232 let vb: *u8 = vp[0] as *u8
233 let vl: i64 = vlp[0]
234 var col0len: i64 = 0
235 var scanning: i64 = 1
236 while scanning == 1 {
237 if col0len >= vl {
238 scanning = 0
239 } else {
240 if (vb[col0len] as i64) == PK_TAB { scanning = 0 } else { col0len = col0len + 1 }
241 }
242 }
243 if col0len == kl0 {
244 var t: i64 = 0
245 var eq: i64 = 1
246 while t < col0len { if vb[t] != key[t] { eq = 0 } t = t + 1 }
247 if eq == 1 {
248 found = 1
249 rk[0] = kp[0]
250 rkl[0] = klp[0]
251 }
252 }
253 }
254 }
255 }
256 return found
257}
258
259// print the value bytes of a hit
260func pk_put_value(pp: *i64, lp: *i64) -> i64 {
261 pk_puts(" len=" as *u8); pk_putn(lp[0])
262 pk_puts("\n " as *u8)
263 sys_write(1, pp[0] as *u8, lp[0])
264 pk_puts("\n" as *u8)
265 return 0
266}
267
268// Resolve ONE key to a fully-qualified state. Returns the exit code for that state and prints the
269// headline. Coverage must already be filled.
270func pk_resolve(prefix: *u8, key: *u8, cov: *i64) -> i64 {
271 let pp: *i64 = sys_mmap(16) as *i64
272 let lp: *i64 = sys_mmap(16) as *i64
273 let r: i64 = ss_get(prefix, key, pp, lp)
274 if r == PK_SS_HIT {
275 pk_puts("HIT " as *u8); pk_puts(key)
276 pk_put_value(pp, lp)
277 return PK_EX_HIT
278 }
279 if r == PK_SS_TOMB {
280 // A TOMBSTONE IS A POSITIVE FACT ABOUT A KEY. v1 printed MISS here, inverting its meaning:
281 // "this row was deleted" and "this row never existed" demand opposite remedies.
282 pk_puts("TOMBSTONED " as *u8); pk_puts(key)
283 pk_puts(" -- the key IS present and carries a DELETE marker (ss_get=0). This is NOT absence.\n" as *u8)
284 return PK_EX_TOMBSTONED
285 }
286 // Absent from every LIVE segment ss_get could read. Before that may be published as absence,
287 // it has to survive two questions v1 never asked.
288 let rk: *i64 = sys_mmap(16) as *i64
289 let rkl: *i64 = sys_mmap(16) as *i64
290 let isval: i64 = pk_scan_for_colvalue(prefix, key, cov, rk, rkl)
291 if isval == 1 {
292 // PRESENCE NEEDS ONE WITNESS: this is valid even under incomplete coverage, so it is
293 // checked BEFORE the UNPROVEN branch.
294 pk_puts("NOT-A-KEY " as *u8); pk_puts(key)
295 pk_puts(" -- that string is COLUMN 0 OF A ROW, not a key. The key of that row is: " as *u8)
296 sys_write(1, rk[0] as *u8, rkl[0])
297 pk_puts("\n Seg-store keys are assigned by the writer (nx_store_put uses q:0..q:n).\n" as *u8)
298 pk_puts(" Retry with that key, or dump the plane: nx_store_put <prefix> load\n" as *u8)
299 return PK_EX_NOTAKEY
300 }
301 if cov[PK_COV_UNREADABLE] > 0 {
302 // ★AN UNBOUNDED SEARCH THAT GIVES UP MUST NOT REPORT THE SAME WORD AS AN EXHAUSTIVE ONE.
303 pk_puts("UNPROVEN " as *u8); pk_puts(key)
304 pk_puts(" -- COVERAGE INCOMPLETE: " as *u8); pk_putn(cov[PK_COV_UNREADABLE])
305 pk_puts(" of " as *u8); pk_putn(cov[PK_COV_DECLARED])
306 pk_puts(" declared segments could not be opened, so absence CANNOT be concluded.\n" as *u8)
307 pk_name_unreadable(prefix, cov)
308 return PK_EX_UNPROVEN
309 }
310 pk_puts("MISS " as *u8); pk_puts(key)
311 pk_puts(" -- PROVEN ABSENT: every declared segment was read and no such key exists.\n" as *u8)
312 return PK_EX_MISS
313}
314
315func main(argc: i64, argv: *i64) -> i64 {
316 if argc < 3 {
317 pk_puts("usage: nx_planepeek <prefix> <key>\n" as *u8)
318 pk_puts(" nx_planepeek <prefix> range <a> <b> (q:<a>..q:<b>, inclusive)\n" as *u8)
319 pk_puts("exits: 0 HIT | 1 MISS(proven) | 2 usage | 3 UNPROVEN | 4 NO-SUCH-PLANE | 5 TOMBSTONED | 6 NOT-A-KEY\n" as *u8)
320 sys_exit(PK_EX_USAGE)
321 }
322 let prefix: *u8 = argv[1] as *u8
323 let a2: *u8 = argv[2] as *u8
324
325 // COVERAGE FIRST, ALWAYS. Nothing may be said about a key before it is known what could be read.
326 let cov: *i64 = sys_mmap(8 * PK_COV_SLOTS) as *i64
327 pk_coverage(prefix, cov)
328 if cov[PK_COV_DECLARED] == 0 {
329 // v1 reported this as MISS -- a mistyped prefix was indistinguishable from a real absence.
330 pk_puts("NO-SUCH-PLANE " as *u8); pk_puts(prefix)
331 pk_puts("\n No live manifest, or it declares zero segments: " as *u8)
332 pk_puts(prefix); pk_puts("manifest.txt\n" as *u8)
333 pk_puts(" Nothing can be concluded about ANY key under this prefix.\n" as *u8)
334 pk_put_coverage(cov)
335 sys_exit(PK_EX_NOPLANE)
336 }
337
338 if pk_streq("range" as *u8, a2) == 1 {
339 if argc < 5 { pk_puts("range needs <a> <b>\n" as *u8); sys_exit(PK_EX_USAGE) }
340 let lo: i64 = pk_atoi(argv[3] as *u8)
341 var hi: i64 = pk_atoi(argv[4] as *u8)
342 // DECLARE THE CLAMP. A peek that silently shortened its own range would be exactly the defect
343 // this whole lane has been measuring all day.
344 if hi - lo + 1 > PK_MAXRANGE {
345 hi = lo + PK_MAXRANGE - 1
346 pk_puts(">>RANGE CLAMPED to " as *u8); pk_putn(PK_MAXRANGE)
347 pk_puts(" keys; the request was wider and the tail is NOT shown.<<\n" as *u8)
348 }
349 let key: *u8 = sys_mmap(PK_KEYCAP)
350 var i: i64 = lo
351 var hits: i64 = 0
352 var tombs: i64 = 0
353 let pp: *i64 = sys_mmap(16) as *i64
354 let lp: *i64 = sys_mmap(16) as *i64
355 while i <= hi {
356 pk_rowkey(i, key)
357 let r: i64 = ss_get(prefix, key, pp, lp)
358 if r == PK_SS_HIT {
359 pk_puts("HIT " as *u8); pk_puts(key); pk_put_value(pp, lp)
360 hits = hits + 1
361 } else {
362 if r == PK_SS_TOMB {
363 pk_puts("TOMBSTONED " as *u8); pk_puts(key); pk_puts("\n" as *u8)
364 tombs = tombs + 1
365 } else {
366 pk_puts("MISS " as *u8); pk_puts(key); pk_puts("\n" as *u8)
367 }
368 }
369 i = i + 1
370 }
371 pk_puts("\nPEEK-RANGE lo=" as *u8); pk_putn(lo)
372 pk_puts(" hi=" as *u8); pk_putn(hi)
373 pk_puts(" hits=" as *u8); pk_putn(hits)
374 pk_puts(" tombstoned=" as *u8); pk_putn(tombs)
375 pk_puts(" miss=" as *u8); pk_putn(hi - lo + 1 - hits - tombs)
376 pk_puts("\n" as *u8)
377 pk_put_coverage(cov)
378 // A range MISS is "no row at that index", which is legitimate; but if the plane could not be
379 // fully read even that is unproven, and the range verb must say so rather than imply a gap.
380 if cov[PK_COV_UNREADABLE] > 0 {
381 pk_puts("UNPROVEN -- " as *u8); pk_putn(cov[PK_COV_UNREADABLE])
382 pk_puts(" declared segments unreadable; MISS lines above are NOT proven absent.\n" as *u8)
383 pk_name_unreadable(prefix, cov)
384 sys_exit(PK_EX_UNPROVEN)
385 }
386 sys_exit(PK_EX_HIT)
387 }
388
389 let code: i64 = pk_resolve(prefix, a2, cov)
390 pk_put_coverage(cov)
391 sys_exit(code)
392 return 0
393}