nx_waitrc_gate.nx
buildroot/runtime/nx_waitrc_gate.nx
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
imports: nx_syscalls.nxnx_gate_verdict.nxnx_tool_run.nxnx_ccbuild_lib.nx
imported by: nobody (leaf or entry point)
structs
| none |
consts
| 33 | const WR_SIGKILL: i64 = 9 |
| 34 | const WR_GUARD_EXIT: i64 = 139 // 128+SIGSEGV, what the crash guard exits with |
| 35 | const WR_CHILD_EXIT: i64 = 7 |
| 36 | const WR_CAP: i64 = 65536 |
| 37 | const WR_DEADLINE_MS: i64 = 20000 |
| 42 | const WR_CHILD_PARK_MS: i64 = 5000 |
| 43 | const WR_CHILD_UNKILLED: i64 = 3 |
functions
| 45 | func wr_puts(s: *u8) -> i64 |
| 52 | func wr_putn(v: i64) -> i64 |
| 72 | func wr_status_of_sigkill() -> i64 |
| 84 | func wr_opaque_zero(argc: i64) -> i64 |
| 89 | func wr_status_of_segv(argc: i64) -> i64 |
| 102 | func wr_status_of_exit(code: i64) -> i64 |
| 110 | func main(argc: i64, argv: *i64) -> i64 |