nx_segopen_incr_gate.nx
buildroot/runtime/nx_segopen_incr_gate.nx
about
nx_segopen_incr_gate.nx -- THE REFEREE FOR ss_open3's INCREMENTAL, WARM-PRESERVING REOPEN (search plan rung L1
ss_open_incr, 2026-09-02). THE CLAIM UNDER TEST: when the manifest is a strict prefix-extension of the handle a
caller already holds, ss_open3(prefix, 1, prev, 1) reuses prev's segment mappings, live maps and key table, loads
only the new rows, clears exactly the old marks the new rows shadow, and produces a handle whose every live map
and every key->newest-row answer is BYTE-IDENTICAL to a FULL open of the same manifest. Any admission failure
(no table retained, a leading name differs, a leading .docs size differs on disk, the manifest shrank) must fall
back to FULL, ANNOUNCE its reason, and leave prev untouched.
FIXTURE, built at runtime in /tmp/<gate>/ (never knowledge/store, which the segguard beat sweeps): three rows
with overlapping keys -- A puts doc:1..40; B re-puts doc:11..20 and tombstones doc:21..25; C re-puts doc:16..18,
tombstones doc:31..35 and adds doc:41..50 -- so the incremental step must clear marks in BOTH older rows (3 in B,
5 in A = 8) through a put AND a tombstone, and leave A's already-dead doc:21..25 alone. The expected mark counts
are computed from the fixture, never read back from the subject: A 25 -> 20, B 10 -> 7, C 13 of 18.
EVERY OUTCOME TOOTH IS PAIRED WITH A FIXTURE-REACHED TOOTH: mapping identity (the moved .docs pointer IS prev's),
prev gutted after the move, the value read through the moved mapping AFTER prev is closed.
GREEN iff every tooth passes; neg-controls named neg-control-* so the gate-law census can count them.
license_tier: ORIGINAL expect_exit: 0
dependencies 3 imports · 0 importers
imports: nx_seg_store.nxnx_syscalls.nxnx_gate_verdict.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 21 | const SI_DIR: *u8 = "/tmp/nx_segopen_incr_gate" |
| 22 | const SI_PREFIX: *u8 = "/tmp/nx_segopen_incr_gate/soi-" |
| 23 | const SI_ERR_PREV: *u8 = "/tmp/nx_segopen_incr_gate/stderr-prev.txt" |
| 24 | const SI_ERR_INCR: *u8 = "/tmp/nx_segopen_incr_gate/stderr-incr.txt" |
| 25 | const SI_ERR_FULL: *u8 = "/tmp/nx_segopen_incr_gate/stderr-full.txt" |
| 26 | const SI_ERR_NEG1: *u8 = "/tmp/nx_segopen_incr_gate/stderr-neg-notable.txt" |
| 27 | const SI_ERR_NEG2: *u8 = "/tmp/nx_segopen_incr_gate/stderr-neg-prefix.txt" |
| 28 | const SI_ERR_NEG3: *u8 = "/tmp/nx_segopen_incr_gate/stderr-neg-size.txt" |
| 29 | const SI_ERR_NEG4: *u8 = "/tmp/nx_segopen_incr_gate/stderr-neg-shrank.txt" |
| 30 | const SI_ERR_FOLD: *u8 = "/tmp/nx_segopen_incr_gate/stderr-fold.txt" |
| 31 | const SI_ERR_FOLDFULL: *u8 = "/tmp/nx_segopen_incr_gate/stderr-fold-full.txt" |
| 32 | const SI_ERR_FS: *u8 = "/tmp/nx_segopen_incr_gate/stderr-fold-ship.txt" |
| 33 | const SI_ERR_UN: *u8 = "/tmp/nx_segopen_incr_gate/stderr-uncovered.txt" |
| 34 | const SI_ERR_UNFULL: *u8 = "/tmp/nx_segopen_incr_gate/stderr-uncovered-full.txt" |
| 35 | const SI_ERR_REO: *u8 = "/tmp/nx_segopen_incr_gate/stderr-reorder.txt" |
| 36 | const SI_ERR_REOFULL: *u8 = "/tmp/nx_segopen_incr_gate/stderr-reorder-full.txt" |
| 37 | const SI_D_LIVE: i64 = 27 // D = latest of A u B: 35 puts, minus C re-puts 16..18 and tombstones 31..35 |
| 38 | const SI_D_LIVE_AFTER_E: i64 = 24 // E re-puts doc:1..3 |
| 39 | const SI_E_LO: i64 = 1 |
| 40 | const SI_E_HI: i64 = 3 |
| 41 | const SI_E_RECS: i64 = 3 |
| 42 | const SI_FOLD_ENTRIES: i64 = 58 // 40 + 18 key entries over [D,C] |
| 43 | const SI_MODE_DIR: i64 = 493 // 0755 |
| 44 | const SI_MODE_FILE: i64 = 420 // 0644 |
| 45 | const SI_SEGCAP: i64 = 65536 |
| 46 | const SI_KIND_LIVE: i64 = 1 |
| 47 | const SI_KIND_TOMB: i64 = 2 |
| 48 | const SI_KEYCAP: i64 = 64 |
| 49 | const SI_VALCAP: i64 = 64 |
| 50 | const SI_PATHCAP: i64 = 512 |
| 51 | const SI_MANCAP: i64 = 4096 |
| 52 | const SI_SAVED_FD: i64 = 20 // where fd 2 is parked while an open's stderr is captured |
| 53 | const SI_A_LO: i64 = 1 // row A: doc:1..40 live |
| 54 | const SI_A_HI: i64 = 40 |
| 55 | const SI_B_LO: i64 = 11 // row B: doc:11..20 re-put, doc:21..25 tombstoned -> 15 records |
| 56 | const SI_B_HI: i64 = 20 |
| 57 | const SI_B_TLO: i64 = 21 |
| 58 | const SI_B_THI: i64 = 25 |
| 59 | const SI_C_LO: i64 = 16 // row C: doc:16..18 re-put, doc:31..35 tombstoned, doc:41..50 new -> 18 records |
| 60 | const SI_C_HI: i64 = 18 |
| 61 | const SI_C_TLO: i64 = 31 |
| 62 | const SI_C_THI: i64 = 35 |
| 63 | const SI_C_NLO: i64 = 41 |
| 64 | const SI_C_NHI: i64 = 50 |
| 65 | const SI_A_RECS: i64 = 40 |
| 66 | const SI_B_RECS: i64 = 15 |
| 67 | const SI_C_RECS: i64 = 18 |
| 68 | const SI_A_LIVE_PREV: i64 = 25 // 40 - 10 re-put by B - 5 tombstoned by B |
| 69 | const SI_B_LIVE_PREV: i64 = 10 |
| 70 | const SI_A_LIVE_AFTER: i64 = 20 // 25 - 5 tombstoned by C |
| 71 | const SI_B_LIVE_AFTER: i64 = 7 // 10 - 3 re-put by C |
| 72 | const SI_C_LIVE: i64 = 13 // 3 re-puts + 10 new; the 5 tombstones carry no mark |
| 73 | const SI_SHADOWED: i64 = 8 // 3 in B + 5 in A |
| 74 | const SI_ENTRIES: i64 = 73 // 40 + 15 + 18 key entries the table comparison must cover |
| 75 | const SI_SUBJECTS: i64 = 16 // opens driven: prev, incr, full, no-table x2, size, reorder x3, shrank x3, fold x2, fold-ship, uncovered x2 |
functions
| 77 | func si_key(out: *u8, i: i64) -> i64 |
| 84 | func si_manifest_path(prefix: *u8, out: *u8) -> i64 |
| 90 | func si_reset(prefix: *u8) -> i64 |
| 97 | func si_marks(h: *i64, s: i64, n: i64) -> i64 called by 1: main |
| 106 | func si_seg_path(prefix: *u8, segname: *u8, suffix: *u8, out: *u8) -> i64 |
| 113 | func si_contains(hay: *u8, hn: i64, needle: *u8) -> i64 called by 1: si_err_has |
| 128 | func si_open_captured(prefix: *u8, errpath: *u8, prev: *i64, retain: i64) -> *i64 |
| 137 | func si_err_has(errpath: *u8, needle: *u8) -> i64 |
| 144 | func si_add_range(wr: *i64, kind: i64, lo: i64, hi: i64, tag: *u8) -> i64 |
| 162 | func si_val_is(h: *i64, key: *u8, expect: *u8) -> i64 |
| 174 | func si_hget_kind(h: *i64, key: *u8) -> i64 |
| 180 | func si_lm_diff(ha: *i64, hb: *i64, s: i64, compared: *i64) -> i64 called by 1: main |
| 196 | func si_table_diff(ha: *i64, hb: *i64, compared: *i64) -> i64 |
| 224 | func si_write_manifest(prefix: *u8, h: *i64, order: *i64, n: i64) -> i64 |
| 244 | func si_write_manifest_names(prefix: *u8, names: *i64, order: *i64, n: i64) -> i64 |
| 261 | func main(argc: i64, argv: *i64) -> i64 |