6969// BUSY_HELD is asserted before PICKED_WITH_BUSY is believed: a precondition
7070// that can evaporate silently is a test that accuses the wrong function.
7171//
72+ // ## The precondition needed an OWNED port, not a picked one — measured
73+ //
74+ // That paragraph was still only half of it, and the other half reddened three
75+ // unrelated PRs in one afternoon, byte-identical every time:
76+ //
77+ // BUSY_HELD=no
78+ // BUSY_PORT=5180
79+ // PICKED_WITH_BUSY=5181
80+ //
81+ // `PICKED_WITH_BUSY=5181` is the picker answering CORRECTLY — asked to avoid
82+ // 5180 it returned 5181. `BUSY_HELD=no` alone is the failure, and the thief was
83+ // this file. The occupier used to bind the port `sdui_pick_free_port` had just
84+ // handed it, and a RESERVATION IS NOT A BIND: the port stays takeable in the gap
85+ // between the pick returning and the occupier binding. `port_held` below binds
86+ // and closes that exact port, and it is spawned within milliseconds of the
87+ // occupier. Measured, 80 trials on an idle container:
88+ //
89+ // probe won the bind 39/80 # the two genuinely race
90+ // occupier died 1/80 # its bind landed inside the probe's hold
91+ //
92+ // Nothing outside this file has to hold 5180 for that to fire, which is why no
93+ // one could name the process that did. So the occupier binds `:0` and reports
94+ // back the port the kernel gave it: it is already holding that port when it
95+ // names it, which is the property BUSY_HELD asserts, and no gap is left.
96+ //
97+ // ## Why `set +e` follows the `source`, and why the harness ends `exit 0`
98+ //
99+ // `scripts/gen-sdui-manifest.sh` is `set -euo pipefail` at its top, so SOURCING
100+ // it turns errexit back ON here, overriding the `set -uo pipefail` written one
101+ // line earlier. Measured rather than read: `case "$-" in *e*)` after the source
102+ // reports `e` set. That is what truncated the three captures above. When the
103+ // occupier had already exited, the cleanup `kill` returned 1, errexit aborted
104+ // the harness on that line, `execFileSync` threw in the `describe` body, and
105+ // vitest reported `0 test` and a bare `Error: Command failed: bash
106+ // /tmp/sdui-collision-*/harness.sh` — every assertion that would have named the
107+ // problem pre-empted, the diagnosis surviving only because stdout rides along
108+ // on the serialized error. Reproduced here: forcing the occupier to lose its
109+ // bind stopped the harness dead after `PICKED_WITH_BUSY`, exit 1, exactly the
110+ // captured shape. So errexit is turned off again AFTER the source, and the
111+ // harness exits 0 unconditionally: its exit status is not a measurement. Every
112+ // measurement is a printed KEY=VALUE line and the assertions below grade those,
113+ // so a precondition that fails now fails AS AN ASSERTION, printing the whole
114+ // `seen` map with it.
115+ //
72116// No vite and no console build: the contract under test is one the shell script
73117// owns, and the ports are picked at run time by the script's own helper so this
74118// test cannot collide with a concurrent agent — which would be a poor look here.
@@ -103,24 +147,31 @@ const HTTP_STUB = [
103147 'const s = http.createServer((_q, r) => { r.writeHead(200); r.end("SERVER"); });' ,
104148 // Losing the bind must EXIT, not throw: an unhandled 'error' event kills the
105149 // harness with a stack trace where a vacuity guard would have named the
106- // problem. See RAW_LISTENER below for the same reasoning.
150+ // problem. See OWNED_LISTENER below for the same reasoning.
107151 's.once("error", () => process.exit(1));' ,
108152 's.listen(Number(process.env.SDUI_TEST_PORT), "127.0.0.1");' ,
109153] . join ( '' ) ;
110154
111155/**
112- * A bare TCP listener on $SDUI_TEST_PORT that reports a lost bind by exiting.
156+ * A bare TCP listener that binds an EPHEMERAL port and prints the one it got.
157+ *
158+ * Bind first, name second. Asking the picker for a port and binding it
159+ * afterwards leaves a window in which anything at all — including `port_held`
160+ * below, measured — can take it, and losing there evaporates the precondition
161+ * the BUSY/STEAL assertions rest on. Port 0 closes the window by construction:
162+ * the number is written from inside the `listening` callback, so by the time
163+ * the harness can read it the socket is already held.
113164 *
114- * The unguarded form of this line is what made the merge-queue failure this
115- * file now pins so hard to read: when a concurrent scanner took the port
116- * first, node threw `Unhandled 'error' event ... EADDRINUSE 127.0.0.1:5180`,
117- * the harness died mid-measurement, and the report was a stack trace instead
118- * of "the port this test meant to occupy was never occupied".
165+ * The error guard stays. It is near-unreachable on `:0`, but the unguarded form
166+ * of this line is what made the merge-queue failure this file pins so hard to
167+ * read: node threw `Unhandled 'error' event ... EADDRINUSE 127.0.0.1:5180`, the
168+ * harness died mid-measurement, and the report was a stack trace instead of
169+ * "the port this test meant to occupy was never occupied".
119170 */
120- const RAW_LISTENER = [
171+ const OWNED_LISTENER = [
121172 'const s = require("node:net").createServer();' ,
122173 's.once("error", () => process.exit(1));' ,
123- 's.listen(Number(process.env.SDUI_TEST_PORT) , "127.0.0.1");' ,
174+ 's.listen(0 , "127.0.0.1", () => console.log(s.address().port) );' ,
124175] . join ( '' ) ;
125176
126177function runHarness ( ) : Record < string , string > {
@@ -137,6 +188,11 @@ function runHarness(): Record<string, string> {
137188 // Sourcing runs no generation — the script returns right after defining
138189 // its helpers, so this exercises the REAL functions.
139190 `source ${ JSON . stringify ( SCRIPT ) } ` ,
191+ // …but the file just sourced opens with `set -euo pipefail`, so the source
192+ // turns errexit back ON here and silently overrides the line above. That
193+ // is what turned a failed precondition into a harness crash and a `0 test`
194+ // report; see the header. Off again, after the source, where it sticks.
195+ 'set +e' ,
140196 `DIR=${ JSON . stringify ( dir ) } ` ,
141197 'NODE_BIN="$(command -v node)"' ,
142198 // "is $1 held right now?" — the same probe shape the script uses, so a
@@ -150,22 +206,42 @@ function runHarness(): Record<string, string> {
150206 'printf "DEV_ARGV=%s\\n" "${ARGV[*]}"' ,
151207 '' ,
152208 '# ── 2. the free-port search skips a port that is taken right now ────' ,
153- 'BUSY="$(sdui_pick_free_port 5180)"' ,
154- 'export SDUI_TEST_PORT="$BUSY"' ,
155- `"$NODE_BIN" -e ${ JSON . stringify ( RAW_LISTENER ) } &` ,
209+ // The busy port is the one the occupier BOUND, not one the picker handed
210+ // it: a reservation is not a bind, and the gap between the two is what
211+ // `port_held` walked through. See the header for the 80-trial count.
212+ 'BUSY_FILE="$DIR/busy.port"' ,
213+ `"$NODE_BIN" -e ${ JSON . stringify ( OWNED_LISTENER ) } > "$BUSY_FILE" &` ,
156214 'BUSY_PID=$!' ,
157215 // disown: otherwise bash prints its own "Killed" job notice when this is
158216 // reaped below, which reads like a test failure in the vitest output.
159217 'disown "$BUSY_PID" 2>/dev/null || true' ,
160- 'for _ in $(seq 1 40); do [ "$(port_held "$BUSY")" = yes ] && break; sleep 0.25; done' ,
218+ // The port appears only once the socket is bound, so waiting for the
219+ // number IS waiting for the hold — there is no second thing to wait for.
220+ 'BUSY=""' ,
221+ 'for _ in $(seq 1 40); do BUSY="$(tr -d "[:space:]" < "$BUSY_FILE" 2>/dev/null || true)"; [ -n "$BUSY" ] && break; sleep 0.25; done' ,
161222 // Vacuity guard, and the one this file was missing when it ejected a PR:
162223 // if the occupier never took the port, the pick below returns it and the
163- // green/red says nothing about the picker.
224+ // green/red says nothing about the picker. Nothing can lose the port to a
225+ // racer any more; the guard stays because it is what would make the next
226+ // way of losing it legible instead of an accusation of the picker.
164227 'printf "BUSY_HELD=%s\\n" "$(port_held "$BUSY")"' ,
165228 'printf "BUSY_PORT=%s\\n" "$BUSY"' ,
229+ // An ephemeral base does not risk scanning off the end of the port space:
230+ // the first candidate is the port we hold, the second is free, and the
231+ // scan returns there rather than walking its 200-port span upward.
166232 'printf "PICKED_WITH_BUSY=%s\\n" "$(sdui_pick_free_port "$BUSY")"' ,
167233 'kill -KILL "$BUSY_PID" 2>/dev/null' ,
168234 '' ,
235+ '# ── 2b. a third sequential pick from the shared base ────────────────' ,
236+ // Case 2 used to contribute one of these as a by-product, back when its
237+ // occupier took its port from the picker. It owns an ephemeral port now,
238+ // so the third pick is taken explicitly: without it the "each pick within
239+ // one run its own port" assertion compares two picked ports against one
240+ // ephemeral one, and those differ whatever the registry does — a guard
241+ // that would go green for a reason unrelated to what it guards.
242+ 'RPORT="$(sdui_pick_free_port 5180)"' ,
243+ 'printf "RPORT=%s\\n" "$RPORT"' ,
244+ '' ,
169245 '# ── 3. a NEIGHBOUR answering on our port is refused, not accepted ───' ,
170246 'NPORT="$(sdui_pick_free_port 5180)"' ,
171247 'printf "NPORT=%s\\n" "$NPORT"' ,
@@ -232,15 +308,21 @@ function runHarness(): Record<string, string> {
232308 // the registry. Against everything else the probe is still the answer,
233309 // and losing there must not leak the claim — a hoarded claim would cost
234310 // a port on every future run in this container.
235- 'SPORT="$(sdui_pick_free_port 5180)"' ,
236- 'export SDUI_TEST_PORT="$SPORT"' ,
237- `"$NODE_BIN" -e ${ JSON . stringify ( RAW_LISTENER ) } &` ,
311+ // Bound, then named — the same precondition case 2 needs, and the same
312+ // way of guaranteeing it. STEAL_HELD is not a weaker assertion than
313+ // BUSY_HELD and had no business resting on a weaker mechanism.
314+ 'STEAL_FILE="$DIR/steal.port"' ,
315+ `"$NODE_BIN" -e ${ JSON . stringify ( OWNED_LISTENER ) } > "$STEAL_FILE" &` ,
238316 'STEAL_PID=$!' ,
239317 'disown "$STEAL_PID" 2>/dev/null || true' ,
240- 'for _ in $(seq 1 40); do [ "$(port_held "$SPORT")" = yes ] && break; sleep 0.25; done' ,
318+ 'SPORT=""' ,
319+ 'for _ in $(seq 1 40); do SPORT="$(tr -d "[:space:]" < "$STEAL_FILE" 2>/dev/null || true)"; [ -n "$SPORT" ] && break; sleep 0.25; done' ,
241320 'printf "STEAL_HELD=%s\\n" "$(port_held "$SPORT")"' ,
242- // A registry of its own, so the listener above is genuinely foreign to
243- // it — the shared registry already knows this port is ours.
321+ // A registry of its own, so the claim files the two lines below read are
322+ // written by this leg and nothing else. The holder is foreign to that
323+ // registry either way, and more plainly than before: a port bound
324+ // directly from the ephemeral range was never claimed in any registry,
325+ // which is exactly the non-participant this case exists to cover.
244326 'RESV="$DIR/resv"' ,
245327 'STEAL_PICK="$( (export SDUI_PORT_RESERVATION_DIR="$RESV"; sdui_pick_free_port "$SPORT") )"' ,
246328 'printf "STEAL_PORT=%s\\n" "$SPORT"' ,
@@ -253,6 +335,15 @@ function runHarness(): Record<string, string> {
253335 // half that can only be true when the registry is real.
254336 'printf "STEAL_CLAIM_ON_PICK=%s\\n" "$([ -e "$RESV/$STEAL_PICK" ] && echo yes || echo no)"' ,
255337 'kill -KILL "$STEAL_PID" 2>/dev/null' ,
338+ '' ,
339+ // Grading belongs to the assertions, not to whatever the last cleanup
340+ // returned. Reaping an occupier that already exited fails, and under the
341+ // errexit this file used to inherit that failure ended the harness where
342+ // it stood; `execFileSync` then threw in the `describe` body and vitest
343+ // reported `0 test` against a bare "Command failed". Exit 0 and let the
344+ // KEY=VALUE lines above be the evidence — a red then names its assertion
345+ // and prints the whole `seen` map beside it.
346+ 'exit 0' ,
256347 ] . join ( '\n' ) ,
257348 { mode : 0o755 } ,
258349 ) ;
@@ -311,7 +402,11 @@ describe.skipIf(!RUNNABLE)('gen-sdui-manifest.sh concurrent-run contract', () =>
311402 } ) ;
312403
313404 it ( 'gives each pick within one run its own port' , ( ) => {
314- const picked = [ seen . BUSY_PORT , seen . NPORT , seen . OPORT ] ;
405+ // Three ports the PICKER handed out, from one base, in one run. BUSY_PORT
406+ // is deliberately not among them any more: the occupier binds an ephemeral
407+ // port of its own, and an ephemeral port differs from the 5180 band however
408+ // the registry behaves, so counting it here would be free.
409+ const picked = [ seen . NPORT , seen . OPORT , seen . RPORT ] ;
315410 expect ( picked . every ( ( p ) => / ^ \d + $ / . test ( p ?? '' ) ) , picked . join ( ',' ) ) . toBe ( true ) ;
316411 expect ( new Set ( picked ) . size , picked . join ( ',' ) ) . toBe ( 3 ) ;
317412 } ) ;
0 commit comments