code wiki / _hdl_build / nx_docportal_search_sticky_gate.nx

nx_docportal_search_sticky_gate.nx

buildroot/runtime/_hdl_build/nx_docportal_search_sticky_gate.nx

14584 B219 linesdepth 5pulls 10 transitivereach 0 importersview sourcekind gate/prooftopic docportal
docsdependenciesstructsconstsfunctions

about

nx_docportal_search_sticky_gate.nx -- does the web-shard cache KEEP its working handle when a reopen comes back EMPTY, and does it refuse to MEMOISE the signature of that empty open? SUBJECT: nx_docportal_search_seg.nx dss_open_maybe_cached, the 2026-08-22 REFUSE-BEFORE-DESTROY fix: let nh: *i64 = ss_open2(prefix, 1) if nh[0] == 0 { ss_close(nh); sys_munmap(cur as *u8, DSC_SIGBUF); return dsc_handle } Until this gate existed that fix was proven BY CONSTRUCTION only. MEASURED 2026-08-22 (pre-fix): one transient empty manifest read destroyed the good handle, installed an empty one, memoised it against the current signature, and every request served total=0 for ~8 minutes on a 1.8 GB / 17-segment index. HOW THE REAL CACHE PATH IS DRIVEN AGAINST A FIXTURE: the cache engages ONLY when the prefix is EXACTLY "knowledge/store/dp-web-pub-" (dsc_web_prefix_is compares the whole literal; dss_prefix builds it from the domain "web"), and that path is RELATIVE. So the gate sys_chdir's into /tmp/<gate>/ and builds knowledge/store/ underneath it: the relative prefix then resolves into the fixture tree and every line of the production open / refresh / guard code runs UNCHANGED -- no test hook, no prefix-override static, no production path touched. The entry CWD (sys_getcwd) is restored before the verdict so gv_journal's relative knowledge/status/harness.jrnl lands where every other gate's does. FIXTURE-RATCHET LAW: all scratch under /tmp/nx_docportal_search_sticky_gate/, created by sys_mkdir at SETUP (a teardown does not run when a run crashes); setup is IDEMPOTENT (the manifest is truncated before the seed commit, so ss_commit -- max_segid+1 under the plane lock -- re-derives seg-1 on every run instead of appending seg-N; stale segment FILES from an earlier run are overwritten or simply never named). TEETH (each states itself; the verdict note does not recount them): T0 accessor reports UNOPENED (-1) before any open (the -1 arm of dss_web_index_segments is real) T1 fixture-reached-condition: healthy fixture opens with segments == 1 (a fixture that cannot fail is not a test) T1b fixture-reached-condition: the cache memoised the HEALTHY manifest signature (size>0, == stat) T2a fixture-reached-condition: the emptied manifest CHANGED the signature, so refresh reaches the reopen branch T5 anti-vacuity: a direct ss_open2 of the emptied manifest returns ns==0 (T2 tests the condition, not a no-op) T2 refresh-keeps-working-handle: refresh over the empty manifest -> still ready, SAME handle, still 1 segment T3 signature-not-memoised: dsc_sig (read via dss_web_cache_sig) still equals the healthy signature, not the empty one T3b WEAK-regression (passes on the pre-fix code too -- named so nobody reads it as discrimination) T4 neg-control-reopen-on-real-change: a manifest naming REAL new segment bytes DOES replace the handle (1 -> 2) T4b the replacement handle really serves the new bytes (ss_hget doc:2 == 1), so T4 counted segments, not names only THIRD STATE: every setup step (mkdir / chdir / prefix / seed) is a gv_need; if one is missing the teeth are NOT run and the gate ends SKIP, never RED -- a broken fixture must not read as a broken subject. WHAT THIS GATE REQUIRES: the two accessors dss_web_index_segments / dss_web_cache_sig in nx_docportal_search_seg.nx (round2 patch A1). Without them it does not compile -- by design: the gate reads STATE, and the state is only readable through them (no importer in the estate reads another module's static; measured over buildroot/runtime, every cross-file mention of a static is a comment). license_tier: ORIGINAL Writes only under /tmp/nx_docportal_search_sticky_gate/. No hw writes (Rule 26).

dependencies 3 imports · 0 importers

nx_docportal_search_seg.nx nx_gate_verdict.nx nx_syscalls.nx nx_docportal_search_sticky_gat

imports: nx_docportal_search_seg.nxnx_gate_verdict.nxnx_syscalls.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main gv_ctr sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ gv_head gv_puts sys_write ↻ sys_mmap ↻ sys_getcwd sys_mmap ↻ sys_mkdir stk_exists sys_mmap ↻ sys_fstatat sys_munmap sys_chdir sys_mmap ↻ dss_prefix dsc_web_prefix_is stk_path ss_writefile sys_openat_wr sys_write ↻ sys_close sys_fsync stk_seed ss_begin

structs

none

consts

47const STK_MANIFEST_SMALL: i64 = 16 // "seg-1" + LF is 6 bytes; 16 is one cache line, never a cap reached
48const STK_LF: i64 = 10 // the manifest row terminator ss_commit_body writes (nb[no] = 10)
49const STK_PUT: i64 = 1 // ss_add kind=1 = put (the kind every seeding gate uses)
50const STK_SEG1: i64 = 1 // first seeded segment id
51const STK_BOX: i64 = 16 // one out-box (ptr or len) -- a page-rounded mmap; the value is the box size, not a cap
52const STK_SEG2: i64 = 2 // second seeded segment id (the neg-control's REAL change)

functions

54func stk_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
called by 1: stk_seed
55func stk_path(out: *u8, a: *u8, b: *u8) -> i64
called by 1: main
63func stk_seed(prefix: *u8, segid: i64, key: *u8, text: *u8) -> i64
called by 1: main calls 4: ss_beginss_addstk_lenss_commit
69func stk_show2(label: *u8, an: *u8, a: i64, bn: *u8, b: i64) -> i64
called by 1: main calls 2: gv_putsgv_num
75func stk_exists(path: *u8) -> i64
called by 1: main calls 3: sys_mmapsys_fstatatsys_munmap
83func main(argc: i64, argv: *i64) -> i64