code wiki / _hdl_build / nx_lease_wedge_gate.nx

nx_lease_wedge_gate.nx

buildroot/runtime/_hdl_build/nx_lease_wedge_gate.nx

21908 B441 linesdepth 7pulls 8 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_lease_wedge_gate.nx -- THE LEASE-WEDGE DETECTOR (2026-09-04). WHY THIS EXISTS. On 2026-09-04 all four knowledge/lease/heavyio-slot-N.lock slots were found PERMANENTLY WEDGED. The crawler AND the shard-compactor had been dead for 18 HOURS and NOTHING in the estate noticed: /search kept answering 200, every daemon read UP, and the only symptom was a status log whose mtime stopped advancing. The operator's report was "search still searches nothing". THE MECHANISM, read out of buildroot/runtime/nx_lease_lib.nx rather than guessed. A takeover is arbitrated by mkdir on a monotonic generation: ls_acquire_root parses the stamp, and for a released or expired lease calls ls_claim(dir, owner, ttl, g_nonce + 1, g_nonce + 1), whose FIRST act is if ls_mkdir(dir + "/g" + gate) != 0 { return 0 } // 0 == LOST == "busy" and whose stamp write is a SEPARATE, LATER, NON-ATOMIC step: let tfd = sys_openat_wr(tp, LS_MODE) ... sys_write ... sys_renameat(tp, sp) A process killed between the mkdir and the rename leaves g<N> ON DISK with the stamp still reading N-1. Every later acquirer then re-derives the SAME gate from the SAME stamp, retries mkdir g<N>, gets EEXIST, and correctly reports BUSY -- forever, with no recovery path and no diagnostic. The host bugchecked 3x in 72 h (GPU driver), which is exactly the kill this window needs. THE TEST IS THE FAILING CALL ITSELF, NOT A PROXY. This gate does not ask "does maxdir exceed the stamp"; it asks the one question that decides the outcome: DOES THE DIRECTORY THE NEXT TAKEOVER WILL TRY TO CREATE ALREADY EXIST? That is stat of <lease>/g<stamp_gen + 1>. A proxy could be right for the wrong reason; this cannot. THE PROBE PATH IS NEVER CREATED. Calling mkdir on g<gen+1> to test for it WOULD ITSELF WEDGE THE LEASE -- the detector would manufacture the defect it reports. Existence is read with fstatat and nothing here writes to a live lease, ever. CHECK-BEFORE-BUILD (rule: "I didn't know it existed" is a retrieval failure). nx_spendgate reports presubmit=FREE and nx_capsearch over 7,341 organs (corpus_complete=1) returns nx_lease and nx_lease_probe -- the PRIMITIVE itself -- plus nx_lease_lib and nx_vault_lease. None censuses lease HEALTH; there is no acquire/release verb that can even express "this lease can never be claimed again". This is a new capability, not a duplicate ruler. SCOPE, STATED SO NOBODY TRUSTS IT AS EXACT: this detects the WEDGE. It does not detect a lease held by a dead process (that is a TTL question and ls_acquire already expires it), and it says nothing about whether the holder is making progress. OWED, DELIBERATELY NOT ATTEMPTED HERE: ls_claim mkdir-then-stamp has no crash recovery. Fixing a shared estate-wide mutex is not a safe act under load, and that file own comments record TWO prior attempts at exactly this which wedged it or double-admitted. A detector first is the right order.

dependencies 3 imports · 0 importers

nx_gate_verdict.nx nx_syscalls.nx nx_lease_lib.nx nx_lease_wedge_gate.nx

imports: nx_gate_verdict.nxnx_syscalls.nxnx_lease_lib.nx

imported by: nobody (leaf or entry point)

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

main gv_head gv_puts sys_write 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 ↻ sys_mmap ↻ lw_clearroot sys_openat_rd sys_mmap ↻ sys_getdents64 dirent_reclen dirent_type dirent_name lw_cat lw_clearlock sys_openat_rd ↻ sys_mmap ↻ sys_getdents64 ↻ dirent_reclen ↻ dirent_name ↻ lw_cat ↻ dirent_type ↻ ls_rmdir sys_unlinkat sys_munmap

structs

none

consts

44const LW_ROOT: *u8 = "knowledge/lease"
45const LW_PATHCAP: i64 = 1024
46const LW_STAMPCAP: i64 = 512
47const LW_DENTBUF: i64 = 65536
48const LW_STATBUF: i64 = 160
49const LW_TAB: i64 = 9
50const LW_NL: i64 = 10
51const LW_D0: i64 = 48
52const LW_D9: i64 = 57
53const LW_B10: i64 = 10
54const LW_GEN_FIELD: i64 = 4
55const LW_DOT: i64 = 46
56const LW_SLASH: i64 = 47
57const LW_SCRATCH: i64 = 32
58const LW_SMALL: i64 = 64
59const LW_BOX: i64 = 16
61const LW_HEALTHY: i64 = 0
62const LW_WEDGED: i64 = 1
63const LW_UNREADABLE: i64 = 2

functions

65func lw_cat(d: *u8, o: i64, s: *u8) -> i64
71func lw_catn(d: *u8, o: i64, v: i64) -> i64
83func lw_pos(v: i64) -> i64 { if v > 0 { return 1 } return 0 }
called by 1: main
85func lw_exists(path: *u8) -> i64
95func lw_stamp_gen(dir: *u8) -> i64
133func lw_classify(dir: *u8, genout: *i64) -> i64
150func lw_census(root: *u8, counts: *i64, verbose: i64) -> i64
213func lw_clearlock(dir: *u8) -> i64
249func lw_clearroot(root: *u8) -> i64
286func lw_rootcount(root: *u8) -> i64
309func lw_mkfix(base: *u8, name: *u8, stamp: *u8, topgen: i64, out: *u8) -> i64
344func main(argc: i64, argv: *i64) -> i64