code wiki / (root) / nx_survey_handoff_gate.nx

nx_survey_handoff_gate.nx source

↩ module page · 460 lines · 20964 B

1// nx_survey_handoff_gate.nx -- TS1 ADOPTION: THE REAL DAEMON, RESTARTED FOR REAL, ZERO DROPS. 2// 3// /compare/trafficsafety rung TS1. nx_ts_handoff_gate already proved the MECHANISM on a synthetic 4// server. This gate proves the ADOPTION, which is the half that was open: it fork+execs the ACTUAL 5// nx_survey_daemon binary, restarts it for real, and measures what a client saw. Nothing here checks 6// that the source references a symbol -- a reference is not an adoption, and the estate has a long 7// record of capabilities that were referenced and never reached. 8// 9// ACCEPT RULE, taken VERBATIM from trafficsafety.plan and not re-invented here: "a swap under a 10// synthetic request stream drops ZERO connections, measured by a client that counts refusals and 11// resets, not by the daemon's own log. The neg-control is mandatory -- the same harness against the 12// CURRENT ordinary-listener path must show a non-zero drop, or the test proves nothing." 13// 14// THE TWO ARMS DIFFER IN EXACTLY ONE THING: whether an owner outside the daemon is publishing the 15// listening socket. Same binary, same argv shape, same client, same request count. In the ARMED arm 16// an owner holds the listener and hands it to each generation, so ts_handoff_nodrop INHERITS it; in 17// the NEG-CONTROL there is no owner, so the very same call falls back to binding -- which is today's 18// behaviour for every other daemon in the estate, and is the disease state. 19// 20// THE DECISIVE MOMENT IS THE ARRIVAL DURING THE GAP. Generation one is killed AND REAPED, so at that 21// instant ZERO daemon processes exist. A client connects right then. With an owner the handshake 22// completes into the kernel's accept queue and generation two serves it; without one there is nothing 23// bound and the arrival is refused with ECONNREFUSED. That difference is deterministic, which is what 24// makes this a gate and not a flaky benchmark. 25// 26// IT ALSO EXERCISES ENVOY'S ORDERING RULE, WHICH IS WHY THE PUBLISH IS THE READINESS SIGNAL. 27// ts_handoff_publish blocks until a generation asks for the socket, and the adopted daemon asks only 28// AFTER it has finished every expensive step (its three arenas and the seg-store warm). So a publish 29// that returns is positive evidence that initialisation completed BEFORE the handoff -- the exact 30// ordering whose absence caused this estate's 8-minute blackout. 31// 32// SAFETY: loopback only; every port is FOUND by a bind that would have failed had it been occupied, 33// because a probe port you did not verify free is not a control, it is a second instance. The live 34// :8031 survey daemon is NEVER touched -- the subject is given its own port on argv precisely so this 35// gate can drive a real restart without becoming a second instance of a running service. The subject 36// runs with CWD inside the gate's own /tmp fixture, so its store self-heal cannot write into a 37// production tree. 38// expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26). 39import "nx_syscalls.nx" 40import "nx_http_server.nx" 41import "nx_gate_emit_lib.nx" 42import "nx_gate_verdict.nx" 43 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 49// sockaddr_in FIELD OFFSETS, named so a reader checks them against the platform layout instead of 50// meeting bare indices: sin_family at 0, sin_port at 2 (big-endian), sin_addr at 4. 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 68// Exit code a child uses when execve itself failed -- an absent artifact must NAME itself rather 69// than surface to the caller as a dead server. 127 is the shell's own convention for not-found. 70const SH_RC_EXEC_FAILED: i64 = 127 71const SH_ARGC_SUBJECT: i64 = 2 72// argv slots of the spawned daemon, named rather than left as bare indices at the call site. 73const SH_AV_PORT: i64 = 1 74const SH_AV_SOCK: i64 = 2 75const SH_AV_END: i64 = 3 76// Both generations of the swap -- the denominator the neg-control's attribution tooth asserts against. 77const SH_BOTH_GENERATIONS: i64 = 2 78 79// The request stream per generation is taken from the rendezvous backlog rather than picked: it 80// exercises the accept queue at the queue's own scale on both sides of the swap. The decisive tooth 81// does not depend on it -- the in-gap arrival is a single deterministic event -- so this number only 82// sets how much "the daemon was really serving" evidence surrounds that event. 83const SH_REQS_PER_GEN: i64 = TS_RV_BACKLOG 84// Bounds exist only so a broken run fails LOUD instead of hanging. Reusing the shim's established 85// socket deadline rather than inventing a second budget for the same kind of wait. 86const SH_DEADLINE_S: i64 = ACCEPT_TMO_S 87// Readiness poll granularity for the NEG-CONTROL arm only. The armed arm needs none -- its publish IS 88// the readiness signal -- but a self-binding daemon offers no such edge, so the harness must retry the 89// connect until the bind lands. This is a harness poll interval, not a product threshold, and the 90// TOTAL wait it participates in is bounded by SH_DEADLINE_S above. 91const SH_READY_POLL_MS: i64 = 20 92const SH_READY_TRIES: i64 = (SH_DEADLINE_S * 1000) / SH_READY_POLL_MS 93 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 101 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 107 108func g_putn(v: i64) -> i64 { 109 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 110 var m: i64 = v 111 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 112 let d: *u8 = sys_mmap(SH_NUM_SCRATCH); var k: i64 = 0 113 while m > 0 { d[k] = ((SH_ASCII_ZERO + (m - (m / SH_B10) * SH_B10)) as u8); m = m / SH_B10; k = k + 1 } 114 var j: i64 = k - 1 115 while j >= 0 { sys_write(1, ((d as i64)+j) as *u8, 1); j = j - 1 } 116 return 0 117} 118 119func gq(label: *u8, got: i64, want: i64, ctr: *i64) -> i64 { 120 var c: i64 = 0 121 if got == want { c = 1 } 122 let r: i64 = gv_check(label, c, ctr) 123 if c == 0 { 124 g_puts(" got=" as *u8); g_putn(got) 125 g_puts(" want=" as *u8); g_putn(want) 126 g_puts("\n" as *u8) 127 } 128 return r 129} 130 131func sh_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 132 133func sh_itoa(v: i64, out: *u8) -> i64 { 134 if v == 0 { out[0] = SH_ASCII_ZERO as u8; out[1] = 0 as u8; return 1 } 135 var m: i64 = v 136 let t: *u8 = sys_mmap(SH_NUM_SCRATCH) 137 var k: i64 = 0 138 while m > 0 { t[k] = ((SH_ASCII_ZERO + (m - (m / SH_B10) * SH_B10)) as u8); m = m / SH_B10; k = k + 1 } 139 var j: i64 = 0 140 while j < k { out[j] = t[k - 1 - j]; j = j + 1 } 141 out[k] = 0 as u8 142 return k 143} 144 145func sh_sa(sa: *u8, port: i64) -> i64 { 146 var i: i64 = 0 147 while i < SH_SA_BYTES { sa[i] = 0; i = i + 1 } 148 // The zero-fill above already cleared every other octet, so only the non-zero lanes are written. 149 sa[0] = AF_INET 150 sa[SH_SA_PORT_OFF] = port / SH_BYTE_RADIX 151 sa[SH_SA_PORT_OFF + 1] = port % SH_BYTE_RADIX 152 sa[SH_SA_ADDR_OFF] = SH_LOOPBACK_A 153 sa[SH_SA_ADDR_OFF + SH_ADDR_BYTES - 1] = SH_LOOPBACK_D 154 return 0 155} 156 157// reuse=0 makes the bind ITSELF the free-port check. 158func sh_listen(port: i64, reuse: i64) -> i64 { 159 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 160 if fd < 0 { return fd } 161 if reuse == SH_TRUE { 162 let ra: *u8 = sys_mmap(SCM_U32_BYTES) 163 var z: i64 = 0 164 while z < SCM_U32_BYTES { ra[z] = 0 as u8; z = z + 1 } 165 ra[0] = 1 166 sys_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, ra, SCM_U32_BYTES) 167 } 168 let sa: *u8 = sys_mmap(SH_SA_BYTES) 169 sh_sa(sa, port) 170 if sys_bind(fd, sa, SH_SA_BYTES) < 0 { sys_close(fd); return 0 - 1 } 171 if sys_listen(fd, TS_RV_BACKLOG) < 0 { sys_close(fd); return 0 - 1 } 172 return fd 173} 174 175func sh_find_port(from: i64) -> i64 { 176 var t: i64 = 0 177 while t < SH_PORT_TRIES { 178 let cand: i64 = from + t 179 let fd: i64 = sh_listen(cand, SH_FALSE) 180 if fd >= 0 { sys_close(fd); return cand } 181 t = t + 1 182 } 183 return SH_PORT_NONE 184} 185 186func sh_connect(port: i64) -> i64 { 187 let sa: *u8 = sys_mmap(SH_SA_BYTES) 188 sh_sa(sa, port) 189 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 190 if fd < 0 { return 0 - 1 } 191 sys_set_socket_timeout(fd, SH_DEADLINE_S) 192 if sys_connect(fd, sa, SH_SA_BYTES) < 0 { sys_close(fd); return 0 - 1 } 193 return fd 194} 195 196// Complete one REAL HTTP exchange on an already-connected socket. 1 = served, 0 = dropped. 197// ANY HTTP response counts as served: this gate measures whether the CONNECTION survived the swap, 198// not whether the application liked the path -- conflating the two would let an app-level 404 read 199// as a dropped connection and would make the number mean nothing. 200func sh_exchange(fd: i64) -> i64 { 201 let n: i64 = sh_slen(SH_REQ) 202 if sys_write(fd, SH_REQ, n) != n { return 0 } 203 let b: *u8 = sys_mmap(SH_RESP_CAP) 204 let r: i64 = sys_read(fd, b, SH_RESP_CAP) 205 // BIND THE LITERAL ONCE AND DERIVE ITS LENGTH. This was four character codes -- 72,84,84,80 -- 206 // which is the string "HTTP" written so no reader recognises it and no grep finds it, with a 207 // hand-counted 4 beside it that would drift the moment the marker changed. 208 let want: *u8 = "HTTP" as *u8 209 var wl: i64 = 0 210 while want[wl] != (0 as u8) { wl = wl + 1 } 211 if r < wl { return 0 } 212 var q: i64 = 0 213 while q < wl { if b[q] != want[q] { return 0 } q = q + 1 } 214 return 1 215} 216 217func sh_drive_one(port: i64) -> i64 { 218 let fd: i64 = sh_connect(port) 219 if fd < 0 { return 0 } 220 let ok: i64 = sh_exchange(fd) 221 sys_close(fd) 222 return ok 223} 224 225// START ONE GENERATION OF THE REAL DAEMON. CWD is moved into the gate's fixture first so the 226// subject's store self-heal cannot write into a production tree. 227func sh_spawn(daemon: *u8, port: i64, sockp: *u8) -> i64 { 228 let pb: *u8 = sys_mmap(SH_NUM_SCRATCH) 229 sh_itoa(port, pb) 230 let pid: i64 = sys_fork() 231 if pid != 0 { return pid } 232 sys_chdir(SH_DIR) 233 let av: *i64 = (sys_mmap(SH_ARGV_BYTES)) as *i64 234 av[0] = daemon as i64 235 av[SH_AV_PORT] = pb as i64 236 av[SH_AV_SOCK] = sockp as i64 237 av[SH_AV_END] = 0 238 let ev: *i64 = (sys_mmap(SH_ARGV_BYTES)) as *i64 239 ev[0] = 0 240 // NOT sys_execve_clean: that closes fds 3..1023, which would destroy an inherited listener. 241 sys_execve(daemon, av, ev) 242 // AN ABSENT ARTIFACT IS INDISTINGUISHABLE FROM A DEAD SERVER unless the exec failure is named. 243 sys_exit(SH_RC_EXEC_FAILED) 244 return 0 245} 246 247func sh_reap(pid: i64) -> i64 { 248 nx_kill(pid, SH_SIG_TERM) 249 let st: *i64 = (sys_mmap(SH_OUT_BYTES)) as *i64 250 st[0] = 0 251 sys_wait4(pid, st, 0) 252 return wait_status_rc(st[0]) 253} 254 255// Wait until a self-binding daemon is actually listening. Bounded, and its success is asserted as an 256// anti-vacuity condition rather than assumed. 257func sh_wait_ready(port: i64) -> i64 { 258 var t: i64 = 0 259 while t < SH_READY_TRIES { 260 let fd: i64 = sh_connect(port) 261 if fd >= 0 { sys_close(fd); return 1 } 262 sys_sleep_ms(SH_READY_POLL_MS) 263 t = t + 1 264 } 265 return 0 266} 267 268// THE EXPERIMENT. Identical script for both arms; the ONLY difference is whether an owner outside the 269// daemon publishes the listening socket. Returns dropped connections, or -1 if the harness could not 270// be set up at all -- which is reported as UNOBSERVED, never as a pass. 271func sh_swap_run(armed: i64, daemon: *u8, port: i64, sockp: *u8, out: *i64) -> i64 { 272 var k: i64 = 0 273 while k < SH_OUT_SLOTS { out[k] = 0; k = k + 1 } 274 out[SH_O_PORT] = port 275 sys_unlinkat(sockp) 276 let vb: *i64 = (sys_mmap(SH_OUT_BYTES)) as *i64 277 vb[0] = 0 278 var rv: i64 = 0 - 1 279 var lsock: i64 = 0 - 1 280 if armed == SH_TRUE { 281 rv = ts_handoff_open(sockp, vb) 282 if rv < 0 { return 0 - 1 } 283 sys_set_socket_timeout(rv, SH_DEADLINE_S) 284 // THE OWNER'S COPY IS THE GUARANTEE: it is opened before any generation exists and closed 285 // only after the last one, so there is no instant at which zero processes hold the port. 286 lsock = sh_listen(port, SH_FALSE) 287 if lsock < 0 { sys_close(rv); return 0 - 1 } 288 } 289 290 var drops: i64 = 0 291 var attempted: i64 = 0 292 var served: i64 = 0 293 294 // ---- generation one 295 let g1: i64 = sh_spawn(daemon, port, sockp) 296 if armed == SH_TRUE { 297 // The publish RETURNS only once the daemon asked for the socket, and it asks only after every 298 // expensive init step -- so this returning is the evidence for Envoy's ordering rule. 299 if ts_handoff_publish(rv, lsock, vb) < 0 { 300 sh_reap(g1); sys_close(rv); sys_close(lsock); sys_unlinkat(sockp); return 0 - 1 301 } 302 out[SH_O_G1READY] = 1 303 } else { 304 out[SH_O_G1READY] = sh_wait_ready(port) 305 if out[SH_O_G1READY] == 0 { sh_reap(g1); return 0 - 1 } 306 } 307 var i: i64 = 0 308 while i < SH_REQS_PER_GEN { 309 attempted = attempted + 1 310 let ok: i64 = sh_drive_one(port) 311 if ok == 1 { served = served + 1 } else { drops = drops + 1 } 312 i = i + 1 313 } 314 315 // ---- THE GAP. Generation one is killed AND REAPED: at this instant ZERO daemon processes exist. 316 sh_reap(g1) 317 let sa: *u8 = sys_mmap(SH_SA_BYTES) 318 sh_sa(sa, port) 319 let gap: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 320 sys_set_socket_timeout(gap, SH_DEADLINE_S) 321 let grc: i64 = sys_connect(gap, sa, SH_SA_BYTES) 322 out[SH_O_GAP_RC] = grc 323 out[SH_O_GAP_DONE] = 1 324 attempted = attempted + 1 325 if grc < 0 { drops = drops + 1 } 326 327 // ---- generation two, which must also serve the in-gap arrival when it survived. 328 let g2: i64 = sh_spawn(daemon, port, sockp) 329 if armed == SH_TRUE { 330 if ts_handoff_publish(rv, lsock, vb) >= 0 { out[SH_O_G2READY] = 1 } 331 } else { 332 out[SH_O_G2READY] = sh_wait_ready(port) 333 } 334 if grc == 0 { 335 if out[SH_O_G2READY] == 1 { 336 if sh_exchange(gap) == 1 { served = served + 1 } else { drops = drops + 1 } 337 } else { drops = drops + 1 } 338 } 339 sys_close(gap) 340 if out[SH_O_G2READY] == 1 { 341 var j: i64 = 0 342 while j < SH_REQS_PER_GEN { 343 attempted = attempted + 1 344 let ok2: i64 = sh_drive_one(port) 345 if ok2 == 1 { served = served + 1 } else { drops = drops + 1 } 346 j = j + 1 347 } 348 } 349 sh_reap(g2) 350 if lsock >= 0 { sys_close(lsock) } 351 if rv >= 0 { sys_close(rv) } 352 sys_unlinkat(sockp) 353 out[SH_O_ATTEMPTED] = attempted 354 out[SH_O_SERVED] = served 355 return drops 356} 357 358func sh_report(tag: *u8, drops: i64, out: *i64) -> i64 { 359 g_puts(" " as *u8); g_puts(tag) 360 g_puts(" port=" as *u8); g_putn(out[SH_O_PORT]) 361 g_puts(" attempted=" as *u8); g_putn(out[SH_O_ATTEMPTED]) 362 g_puts(" served=" as *u8); g_putn(out[SH_O_SERVED]) 363 g_puts(" drops=" as *u8); g_putn(drops) 364 g_puts(" in_gap_connect_rc=" as *u8); g_putn(out[SH_O_GAP_RC]) 365 g_puts(" gen1_ready=" as *u8); g_putn(out[SH_O_G1READY]) 366 g_puts(" gen2_ready=" as *u8); g_putn(out[SH_O_G2READY]) 367 g_puts("\n" as *u8) 368 return 0 369} 370 371func main(argc: i64, argv: **u8) -> i64 { 372 let ctr: *i64 = gv_ctr() 373 gv_head("nx_survey_handoff_gate -- TS1 ADOPTION: the REAL daemon restarted, measured in drops" as *u8) 374 375 var daemon: *u8 = SH_DEFAULT_DAEMON 376 if argc >= SH_ARGC_SUBJECT { daemon = argv[1] as *u8 } 377 g_puts(" subject=" as *u8); g_puts(daemon); g_puts("\n" as *u8) 378 379 sys_mkdir(SH_DIR, MODE_0755) 380 sys_unlinkat(SH_SOCK_ARMED) 381 sys_unlinkat(SH_SOCK_NEG) 382 383 // THE SUBJECT MUST EXIST. An absent artifact is indistinguishable from a dead server, so this is 384 // established before anything is measured rather than being read out of a confusing failure. 385 let dl: *i64 = (sys_mmap(SH_OUT_BYTES)) as *i64 386 dl[0] = 0 387 let probe: *u8 = sys_read_file(daemon, dl) 388 var have: i64 = 0 389 if probe != (0 as *u8) { if dl[0] > 0 { have = 1 } } 390 g_puts(" subject_bytes=" as *u8); g_putn(dl[0]); g_puts("\n" as *u8) 391 if gv_need("the subject binary exists and is readable" as *u8, have, ctr) == 0 { 392 let rcs: i64 = gv_verdict("SURVEY-HANDOFF-GATE" as *u8, ctr, "each tooth states its own strength above" as *u8) 393 sys_exit(rcs) 394 return rcs 395 } 396 397 let pa: i64 = sh_find_port(SH_PORT_BASE) 398 var pn: i64 = SH_PORT_NONE 399 if pa != SH_PORT_NONE { pn = sh_find_port(pa + 1) } 400 var ports_ok: i64 = 0 401 if pa != SH_PORT_NONE { if pn != SH_PORT_NONE { if pa != pn { ports_ok = 1 } } } 402 if gv_need("two DISTINCT loopback ports proven free by a bind without SO_REUSEADDR" as *u8, ports_ok, ctr) == 0 { 403 let rcs: i64 = gv_verdict("SURVEY-HANDOFF-GATE" as *u8, ctr, "each tooth states its own strength above" as *u8) 404 sys_exit(rcs) 405 return rcs 406 } 407 gq("T01 the two arms run on DIFFERENT ports so neither can serve the other" as *u8, pa != pn, 1, ctr) 408 409 // ---- ARM 1: ADOPTED. An owner outside the daemon holds the listener. 410 let oa: *i64 = (sys_mmap(SH_OUT_BYTES)) as *i64 411 let da: i64 = sh_swap_run(SH_TRUE, daemon, pa, SH_SOCK_ARMED, oa) 412 sh_report("ADOPTED " as *u8, da, oa) 413 var arm_ran: i64 = 0 414 if da >= 0 { if oa[SH_O_GAP_DONE] == 1 { arm_ran = 1 } } 415 if gv_need("the ADOPTED arm reached the restart with a live request stream" as *u8, arm_ran, ctr) == 1 { 416 // ANTI-VACUITY FIRST: a restart with nothing in flight is UNOBSERVED, never a pass. The 417 // denominator is asserted arithmetically before any verdict about drops is believed. 418 gq("T02 anti-vacuity the ADOPTED arm drove the whole stream across the restart" as *u8, 419 oa[SH_O_ATTEMPTED], SH_REQS_PER_GEN + SH_REQS_PER_GEN + 1, ctr) 420 gq("T03 generation one really served before it was killed and reaped" as *u8, oa[SH_O_G1READY], 1, ctr) 421 gq("T04 ENVOY ORDERING generation two finished its expensive init BEFORE taking the socket" as *u8, 422 oa[SH_O_G2READY], 1, ctr) 423 gq("T05 THE INVARIANT an arrival DURING the restart is not refused" as *u8, oa[SH_O_GAP_RC], 0, ctr) 424 gq("T06 THE ACCEPT RULE zero dropped connections across a REAL restart of the real daemon" as *u8, da, 0, ctr) 425 gq("T07 and every attempted connection was served end to end" as *u8, oa[SH_O_SERVED], oa[SH_O_ATTEMPTED], ctr) 426 } 427 428 // ---- ARM 2: NEG-CONTROL. Same binary, same harness, NO owner -- so ts_handoff_nodrop falls back 429 // to binding, which is what every other daemon in the estate still does. If this does not drop, 430 // the adopted arm's zero proves nothing at all. 431 let on: *i64 = (sys_mmap(SH_OUT_BYTES)) as *i64 432 let dn: i64 = sh_swap_run(SH_FALSE, daemon, pn, SH_SOCK_NEG, on) 433 sh_report("NEG-CTRL" as *u8, dn, on) 434 var neg_ran: i64 = 0 435 if dn >= 0 { if on[SH_O_GAP_DONE] == 1 { neg_ran = 1 } } 436 if gv_need("the NEG-CONTROL arm reached the restart with a live request stream" as *u8, neg_ran, ctr) == 1 { 437 gq("T08 neg-control-same-denominator it drove the same number of connections" as *u8, 438 on[SH_O_ATTEMPTED], oa[SH_O_ATTEMPTED], ctr) 439 var refused: i64 = 0 440 if on[SH_O_GAP_RC] < 0 { refused = 1 } 441 gq("T09 neg-control-bind-per-process the in-gap arrival IS refused" as *u8, refused, 1, ctr) 442 var lost: i64 = 0 443 if dn > 0 { lost = 1 } 444 gq("T10 neg-control-drops the un-adopted path loses connections across a restart" as *u8, lost, 1, ctr) 445 // The control must fail for the RIGHT reason: the port went away, not the harness broke. 446 gq("T11 neg-control-attribution both of its generations really served" as *u8, 447 on[SH_O_G1READY] + on[SH_O_G2READY], SH_BOTH_GENERATIONS, ctr) 448 // Both signals present at once: two arms that each isolate one signal do not prove the 449 // mechanism discriminates between them. 450 var better: i64 = 0 451 if da >= 0 { if dn > da { better = 1 } } 452 gq("T12 the adopted daemon strictly beats its own un-adopted path on the SAME harness" as *u8, better, 1, ctr) 453 } 454 455 sys_unlinkat(SH_SOCK_ARMED) 456 sys_unlinkat(SH_SOCK_NEG) 457 let rc: i64 = gv_verdict("SURVEY-HANDOFF-GATE" as *u8, ctr, "each tooth states its own strength above" as *u8) 458 sys_exit(rc) 459 return rc 460}