code wiki / (root) / nx_joblost_gate.nx

nx_joblost_gate.nx

buildroot/runtime/nx_joblost_gate.nx

36156 B623 linesdepth 3pulls 5 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_joblost_gate.nx -- WHICH ASYNC JOBS DIED, as distinct from which are still running. WHY THIS EXISTS, measured 2026-08-07. Under load (loadavg 18.18 on the 8-thread box, nx_tools_api_se in D-state, /api/health 503 "upstream backend gave no response inside the edge window") nx_tools_api claims a job id with O_CREAT|O_EXCL and can then die before the worker ever produces output. The caller gets the bare JSON object `{}`. Two of my writes were destroyed that way inside five minutes and I only noticed because I happened to read the row back. The estate's standing rule for a dropped response -- VERIFY BY ARTEFACT -- fails silently here, because the artefact was never written and the job record is EMPTY rather than ABSENT. --------------------------------------------------------------------------------------------- v1 OF THIS GATE WAS WRONG AND SHIPPED GREEN. It counted every zero-byte .claim as a LOST job. Reading nx_tools_api afterwards showed the claim is created EMPTY and only filled at completion (ta_job_put -> sys_renameat), so a zero-byte claim is ALSO the normal representation of a job that is still RUNNING. v1 therefore merged "in flight" with "died" under the alarming name. ★★★★★★ I WROTE "UNKNOWN IS ITS OWN BUCKET" INTO THIS FILE'S OWN HEADER AND THEN BROKE IT IN THE SAME HOUR. A LAW YOU CAN RECITE IS NOT A LAW YOU HAVE APPLIED. v1 also declared the imprecision as unavoidable -- "separating in flight from wedged needs a clock and this gate does not have one". IT HAD ONE ALL ALONG: the job id IS the epoch second, printed in every filename. ★★★★★★ THE INFORMATION I DECLARED UNAVAILABLE WAS ENCODED IN THE NAME OF THE FILE I WAS ALREADY READING. "THIS CANNOT BE MEASURED" IS A CLAIM THAT MUST BE EARNED, EXACTLY LIKE ANY OTHER. FIVE BUCKETS, each with a different remedy, none folded into another: DONE state=DONE was written -- healthy, nothing to do INFLIGHT empty claim, no .out, young -- probably running; NOT an alarm LOST empty claim, no .out, OLD -- the id was reserved and nothing ever came back ORPHAN empty claim but .out EXISTS -- the worker produced output and never renamed the claim, so a poller waiting on state=DONE waits forever REAPED a tombstone was APPENDED -- adjudicated and closed by nx_jobclaim_reap; the claim keeps its original marker, so only a reader that tests REAPED FIRST can see it (2026-08-20) The age threshold is DECLARED and argv-overridable, and it is deliberately generous: jobs run with tmo=0 (no timeout) precisely so they can outlive the request window, so a tight bound would accuse healthy long jobs. ★ A HEURISTIC THAT GATES AN ALARM MUST BE WRONG IN THE DIRECTION OF SILENCE. license_tier: ORIGINAL expect_exit: 0

dependencies 3 imports · 0 importers

syscalls.nx nx_gate_verdict.nx nx_jobclaim_lib.nx nx_joblost_gate.nx

imports: syscalls.nxnx_gate_verdict.nxnx_jobclaim_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_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 ↻ jr_maxage sys_read_file sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_munmap sys_close sys_free_file sys_munmap ↻ sys_mmap ↻ jr_num_from jr_atoi_strict jr_slen jl_clean jl_slen jl_mkname jl_touch jl_slen ↻ jr_tombstone

structs

none

consts

44const JL_JOBS: *u8 = "_jobs" as *u8
45const JL_RATCHET: *u8 = "knowledge/status/joblost_ratchet.conf" as *u8
46const JL_DEFAULT_FLOOR: i64 = 0
56const JL_DBUF: i64 = 65536
57const JL_FBUF: i64 = 4096
58const JL_PATH: i64 = 1024
59const JL_MODE: i64 = 420
61const JL_TOTAL: i64 = 0
62const JL_DONE: i64 = 1
63const JL_INFLIGHT: i64 = 2
64const JL_LOST: i64 = 3
65const JL_ORPHAN: i64 = 4
66const JL_UNKNOWN: i64 = 5
76const JL_REAPED: i64 = 6
80const JL_SLOTS: i64 = 7
86const JL_IDBASE: i64 = 8
87const JL_LOSTCAP: i64 = 32

functions

89func jl_slen(p: *u8) -> i64
100func jl_ends_claim(nm: *u8, nl: i64) -> i64
called by 1: jl_scan
110func jl_parse_id(nm: *u8, nl: i64) -> i64
called by 1: jl_scan
127func jl_read(path: *u8, buf: *u8, cap: i64) -> i64
called by 3: jl_scanjl_floormain
140func jl_exists(path: *u8) -> i64
called by 1: jl_scan
150func jl_scan(dir: *u8, now: i64, maxage: i64, out: *i64, dbuf: *u8, fbuf: *u8, pbuf: *u8) -> i64
257func jl_clean(dir: *u8, dbuf: *u8, pbuf: *u8) -> i64
called by 1: main calls 1: jl_slen
295func jl_touch(path: *u8, body: *u8) -> i64
called by 1: main calls 1: jl_slen
305func jl_mkname(buf: *u8, dir: *u8, id: i64, ext: *u8) -> i64
called by 1: main
325func jl_floor(defaulted: *i64, fbuf: *u8, seen: *i64) -> i64
called by 1: main calls 2: jl_readjr_num_from
340func main(argc: i64, argv: *i64) -> i64