code wiki / (root) / nx_survey_handoff_gate.nx

nx_survey_handoff_gate.nx

buildroot/runtime/nx_survey_handoff_gate.nx

20964 B460 linesdepth 4pulls 6 transitivereach 0 importersview sourcekind gate/prooftopic survey
docsdependenciesstructsconstsfunctions

about

nx_survey_handoff_gate.nx -- TS1 ADOPTION: THE REAL DAEMON, RESTARTED FOR REAL, ZERO DROPS. /compare/trafficsafety rung TS1. nx_ts_handoff_gate already proved the MECHANISM on a synthetic server. This gate proves the ADOPTION, which is the half that was open: it fork+execs the ACTUAL nx_survey_daemon binary, restarts it for real, and measures what a client saw. Nothing here checks that the source references a symbol -- a reference is not an adoption, and the estate has a long record of capabilities that were referenced and never reached. ACCEPT RULE, taken VERBATIM from trafficsafety.plan and not re-invented here: "a swap under a synthetic request stream drops ZERO connections, measured by a client that counts refusals and resets, not by the daemon's own log. The neg-control is mandatory -- the same harness against the CURRENT ordinary-listener path must show a non-zero drop, or the test proves nothing." THE TWO ARMS DIFFER IN EXACTLY ONE THING: whether an owner outside the daemon is publishing the listening socket. Same binary, same argv shape, same client, same request count. In the ARMED arm an owner holds the listener and hands it to each generation, so ts_handoff_nodrop INHERITS it; in the NEG-CONTROL there is no owner, so the very same call falls back to binding -- which is today's behaviour for every other daemon in the estate, and is the disease state. THE DECISIVE MOMENT IS THE ARRIVAL DURING THE GAP. Generation one is killed AND REAPED, so at that instant ZERO daemon processes exist. A client connects right then. With an owner the handshake completes into the kernel's accept queue and generation two serves it; without one there is nothing bound and the arrival is refused with ECONNREFUSED. That difference is deterministic, which is what makes this a gate and not a flaky benchmark. IT ALSO EXERCISES ENVOY'S ORDERING RULE, WHICH IS WHY THE PUBLISH IS THE READINESS SIGNAL. ts_handoff_publish blocks until a generation asks for the socket, and the adopted daemon asks only AFTER it has finished every expensive step (its three arenas and the seg-store warm). So a publish that returns is positive evidence that initialisation completed BEFORE the handoff -- the exact ordering whose absence caused this estate's 8-minute blackout. SAFETY: loopback only; every port is FOUND by a bind that would have failed had it been occupied, because a probe port you did not verify free is not a control, it is a second instance. The live :8031 survey daemon is NEVER touched -- the subject is given its own port on argv precisely so this gate can drive a real restart without becoming a second instance of a running service. The subject runs with CWD inside the gate's own /tmp fixture, so its store self-heal cannot write into a production tree. expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 4 imports · 0 importers

nx_syscalls.nx nx_http_server.nx nx_gate_emit_lib.nx nx_gate_verdict.nx nx_survey_handoff_gate.nx

imports: nx_syscalls.nxnx_http_server.nxnx_gate_emit_lib.nxnx_gate_verdict.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 ↻ g_puts sys_write ↻ sys_mkdir sys_unlinkat sys_mmap ↻ sys_read_file sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_munmap sys_close g_putn sys_write ↻ sys_mmap ↻ gv_need gv_puts ↻ gv_verdict gv_note_bare_rate gv_bare_rate

structs

none

consts

44const SH_NUM_SCRATCH: i64 = 24
45const SH_ASCII_ZERO: i64 = 48
46const SH_B10: i64 = 10
47const SH_ONE: i64 = 1
48const SH_SA_BYTES: i64 = 16
51const SH_SA_PORT_OFF: i64 = 2
52const SH_SA_ADDR_OFF: i64 = 4
53const SH_ADDR_BYTES: i64 = 4
54const SH_BYTE_RADIX: i64 = 256
55const SH_OUT_SLOTS: i64 = 12
56const SH_OUT_BYTES: i64 = 128
57const SH_LOOPBACK_A: i64 = 127
58const SH_LOOPBACK_D: i64 = 1
59const SH_PORT_BASE: i64 = 39500
60const SH_PORT_TRIES: i64 = 64
61const SH_PORT_NONE: i64 = 0 - 1
62const SH_TRUE: i64 = 1
63const SH_FALSE: i64 = 0
64const SH_PATHBUF: i64 = 256
65const SH_ARGV_BYTES: i64 = 64
66const SH_RESP_CAP: i64 = 4096
67const SH_SIG_TERM: i64 = 15
70const SH_RC_EXEC_FAILED: i64 = 127
71const SH_ARGC_SUBJECT: i64 = 2
73const SH_AV_PORT: i64 = 1
74const SH_AV_SOCK: i64 = 2
75const SH_AV_END: i64 = 3
77const SH_BOTH_GENERATIONS: i64 = 2
83const SH_REQS_PER_GEN: i64 = TS_RV_BACKLOG
86const SH_DEADLINE_S: i64 = ACCEPT_TMO_S
91const SH_READY_POLL_MS: i64 = 20
92const SH_READY_TRIES: i64 = (SH_DEADLINE_S * 1000) / SH_READY_POLL_MS
94const SH_O_ATTEMPTED: i64 = 0
95const SH_O_SERVED: i64 = 1
96const SH_O_GAP_RC: i64 = 2
97const SH_O_GAP_DONE: i64 = 3
98const SH_O_PORT: i64 = 4
99const SH_O_G1READY: i64 = 5
100const SH_O_G2READY: i64 = 6
102const SH_DIR: *u8 = "/tmp/nx_survey_handoff_gate" as *u8
103const SH_SOCK_ARMED: *u8 = "/tmp/nx_survey_handoff_gate/armed.sock" as *u8
104const SH_SOCK_NEG: *u8 = "/tmp/nx_survey_handoff_gate/neg.sock" as *u8
105const SH_DEFAULT_DAEMON: *u8 = "./nx_survey_daemon.elf" as *u8
106const SH_REQ: *u8 = "GET /survey HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" as *u8

functions

108func g_putn(v: i64) -> i64
called by 3: gqsh_reportmain calls 2: sys_writesys_mmap
119func gq(label: *u8, got: i64, want: i64, ctr: *i64) -> i64
called by 1: main calls 3: gv_checkg_putsg_putn
131func sh_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
called by 1: sh_exchange
133func sh_itoa(v: i64, out: *u8) -> i64
called by 1: sh_spawn calls 1: sys_mmap
145func sh_sa(sa: *u8, port: i64) -> i64
158func sh_listen(port: i64, reuse: i64) -> i64
175func sh_find_port(from: i64) -> i64
called by 1: main calls 2: sh_listensys_close
186func sh_connect(port: i64) -> i64
200func sh_exchange(fd: i64) -> i64
217func sh_drive_one(port: i64) -> i64
227func sh_spawn(daemon: *u8, port: i64, sockp: *u8) -> i64
247func sh_reap(pid: i64) -> i64
257func sh_wait_ready(port: i64) -> i64
271func sh_swap_run(armed: i64, daemon: *u8, port: i64, sockp: *u8, out: *i64) -> i64
358func sh_report(tag: *u8, drops: i64, out: *i64) -> i64
called by 1: main calls 2: g_putsg_putn
371func main(argc: i64, argv: **u8) -> i64