code wiki / (root) / nx_waitrc_gate.nx

nx_waitrc_gate.nx

buildroot/runtime/nx_waitrc_gate.nx

10353 B209 linesdepth 5pulls 7 transitivereach 0 importersview sourcekind gate/proof
docsdependenciesstructsconstsfunctions

about

nx_waitrc_gate.nx -- A CRASHED OR KILLED PROCESS MUST NOT READ AS A CLEAN ONE. THE DEFECT, MEASURED 2026-08-25 ON THE LIVE SURFACE: a gate that died mid-run was served by /api/gate_run as exit_code 0, verdict GREEN. One line causes it. wait_exit_code is WEXITSTATUS, bits 8-15 of the wait status, and a child killed by a SIGNAL has no exit status at all -- those bits are ZERO. So a signal death and a clean exit 0 are THE SAME VALUE to any caller reading only that accessor, and nx_tool_run's tr_run_capture family -- the exec primitive behind /api/gate_run, /api/build and 51 other consumers -- read only that accessor. WHY SIGKILL AND NOT SIGSEGV, WHICH IS WHAT THIS GATE FIRST TESTED AND WHY THAT RUN WAS RED. The first fixture segfaulted a child and asserted a signal death. It got termsig=0, exit=139, and the fixture-reached-condition tooth FAILED -- correctly. This estate ships a DEFAULT-ON CRASH GUARD: it catches SIGSEGV/SIGBUS/SIGILL/SIGFPE, prints the faulting instruction and address, and ends the process with EXIT 139 rather than re-raising. So for a guarded NishiLang binary a segfault ALREADY surfaces as a non-zero exit code and wait_exit_code is already right about it. SIGKILL cannot be caught, blocked or handled by any guard, and it is the signal that actually bit this estate: nx_gatekit_lib records two gates the 60 s watchdog KILLED journaling GREEN exit=0 ms=60443. A WATCHDOG-KILLED SUBJECT THAT RETURNS THE EXIT CODE OF A CLEAN ONE TURNS EVERY TIMEOUT INTO A PASS. That is the class under test, so the fixture must die the way the real ones died. THE FIRST RED WAS THE FIXTURE FAILING TO REACH THE CONDITION, NOT THE RULE FAILING -- WHICH IS EXACTLY WHAT THAT TOOTH EXISTS TO SEPARATE, AND WHY THE ANSWER WAS TO FIX THE FIXTURE AND NEVER TO WIDEN THE ASSERTION. The DISAGREE tooth is the discriminator and the reason this gate cannot go quiet: it feeds ONE status word to the old accessor and the new ruler and demands they DISAGREE. If wait_status_rc ever silently became wait_exit_code again, that tooth is what notices.

dependencies 4 imports · 0 importers

nx_syscalls.nx nx_gate_verdict.nx nx_tool_run.nx nx_ccbuild_lib.nx nx_waitrc_gate.nx

imports: nx_syscalls.nxnx_gate_verdict.nxnx_tool_run.nxnx_ccbuild_lib.nx

imported by: nobody (leaf or entry point)

structs

none

consts

33const WR_SIGKILL: i64 = 9
34const WR_GUARD_EXIT: i64 = 139 // 128+SIGSEGV, what the crash guard exits with
35const WR_CHILD_EXIT: i64 = 7
36const WR_CAP: i64 = 65536
37const WR_DEADLINE_MS: i64 = 20000
42const WR_CHILD_PARK_MS: i64 = 5000
43const WR_CHILD_UNKILLED: i64 = 3

functions

45func wr_puts(s: *u8) -> i64
52func wr_putn(v: i64) -> i64
72func wr_status_of_sigkill() -> i64
84func wr_opaque_zero(argc: i64) -> i64
89func wr_status_of_segv(argc: i64) -> i64
102func wr_status_of_exit(code: i64) -> i64
110func main(argc: i64, argv: *i64) -> i64