nx_ts_slot_router_gate.nx
buildroot/runtime/nx_ts_slot_router_gate.nx
about
nx_ts_slot_router_gate.nx -- TS3: A FLIP THE CLIENT CANNOT SEE, AND A COLD SLOT IT REFUSES.
/compare/trafficsafety rung TS3, accept rule taken VERBATIM from trafficsafety.plan and not
re-invented here: "a flip changes which slot answers with zero failed requests across the flip, a
slot that fails its warm-up probe is NEVER flipped to, and the front door's own uptime is unbroken
across the whole exercise."
ALL THREE CONJUNCTS ARE TESTED SEPARATELY AND EACH NAMES ITSELF, because a compound assertion that
will not name its failing conjunct is a false-alarm generator -- the reader always guesses the
alarming third.
THE SUBJECT IS THE REAL ROUTER BINARY, fork+exec'd, not a function called in-process. And the gate
plays OWNER of the front listener, handing it over with ts_handoff_publish, which does double duty:
it is a deterministic readiness edge (the publish returns only once the router asked for the
socket) AND it demonstrates the property TS3's own risk row demands -- that the one component which
must never restart is itself replaceable without a gap, which is why TS3 depends on TS1.
THE COLD-SLOT CONTROL IS A REAL DEATH, NOT A FICTION. Slot A's server is killed AND its listening
socket closed, so the port genuinely refuses connections; only then is a flip back to A attempted.
A guard that gates a destructive action must be wrong in the direction of doing nothing, and moving
live traffic onto a dead slot is the destructive action here -- so the control asserts three things,
not one: that the flip was REFUSED BY NAME, that the active slot did not move, and that the client
still reaches the healthy slot afterwards. A refusal that quietly parked traffic nowhere would pass
the first and fail the third.
SAFETY: loopback only; every port is FOUND by a bind that would have failed had it been occupied.
Nothing live is touched -- this router is standalone by design and fronts only the gate's own two
throwaway slot servers. Fixtures live under /tmp/<gate>/ and setup clears them, so a run cannot
inherit a previous run's state file and report on it.
expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26).
dependencies 5 imports · 0 importers
imports: nx_syscalls.nxnx_http_server.nxnx_ts_slot_lib.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
structs
| none |
consts
| 37 | const TG_NUM_SCRATCH: i64 = 24 |
| 38 | const TG_ASCII_ZERO: i64 = 48 |
| 39 | const TG_B10: i64 = 10 |
| 40 | const TG_SA_BYTES: i64 = 16 |
| 43 | const TG_SA_PORT_OFF: i64 = 2 |
| 44 | const TG_SA_ADDR_OFF: i64 = 4 |
| 45 | const TG_ADDR_BYTES: i64 = 4 |
| 46 | const TG_BYTE_RADIX: i64 = 256 |
| 47 | const TG_OUT_BYTES: i64 = 128 |
| 48 | const TG_LOOPBACK_A: i64 = 127 |
| 49 | const TG_LOOPBACK_D: i64 = 1 |
| 50 | const TG_PORT_BASE: i64 = 39700 |
| 51 | const TG_PORT_TRIES: i64 = 64 |
| 52 | const TG_PORT_NONE: i64 = 0 - 1 |
| 53 | const TG_TRUE: i64 = 1 |
| 54 | const TG_FALSE: i64 = 0 |
| 55 | const TG_BUF: i64 = 4096 |
| 56 | const TG_ARGV_BYTES: i64 = 64 |
| 57 | const TG_SIG_TERM: i64 = 15 |
| 58 | const TG_ARGC_SUBJECT: i64 = 2 |
| 61 | const TG_F_SETFD: i64 = 2 |
| 62 | const TG_FD_CLOEXEC: i64 = 1 |
| 63 | const TG_AV_FRONT: i64 = 1 |
| 64 | const TG_AV_SLOTA: i64 = 2 |
| 65 | const TG_AV_SLOTB: i64 = 3 |
| 66 | const TG_AV_STATE: i64 = 4 |
| 67 | const TG_AV_SOCK: i64 = 5 |
| 68 | const TG_AV_END: i64 = 6 |
| 71 | const TG_RC_EXEC_FAILED: i64 = 127 |
| 72 | const TG_DEADLINE_S: i64 = ACCEPT_TMO_S |
| 73 | const TG_MARK_A: i64 = 65 |
| 74 | const TG_MARK_B: i64 = 66 |
| 75 | const TG_PROBE: i64 = 80 |
| 78 | const TG_REQS: i64 = TSR_BACKLOG |
| 80 | const TG_DIR: *u8 = "/tmp/nx_ts_slot_router_gate" as *u8 |
| 81 | const TG_STATE: *u8 = "/tmp/nx_ts_slot_router_gate/slots.conf" as *u8 |
| 82 | const TG_SOCK: *u8 = "/tmp/nx_ts_slot_router_gate/front.sock" as *u8 |
| 83 | const TG_DEFAULT_ROUTER: *u8 = "./nx_ts_slot_router.elf" as *u8 |
functions
| 85 | func g_putn(v: i64) -> i64 |
| 96 | func gq(label: *u8, got: i64, want: i64, ctr: *i64) -> i64 |
| 108 | func tg_sa(sa: *u8, port: i64) -> i64 |
| 120 | func tg_listen(port: i64, reuse: i64) -> i64 |
| 148 | func tg_find_port(from: i64) -> i64 |
| 161 | func tg_slot_server(lfd: i64, marker: i64) -> i64 |
| 179 | func tg_ask(front: i64) -> i64 |
| 196 | func tg_drive(front: i64, want: i64, out: *i64) -> i64 |
| 210 | func tg_write_state(slot: i64) -> i64 |
| 228 | func tg_spawn_router(router: *u8, front: i64, pa: i64, pb: i64) -> i64 |
| 252 | func main(argc: i64, argv: **u8) -> i64 |