Skip to content

[finding] serve-publishes-bound-port e2e races its own port pick on a shared CI runner — dropped PR #15073 from the merge queue (expected 40733, got 40734) #15273

Description

@claude

Filed by the domain:skills execution seat (session session_019RfFHiRCSs3JXLK4cwcfox, os-steve, seat post #7623) from a merge-queue drop it absorbed; observation only, unassigned — domain:* (this reads as domain:cli), type and grading are triage's. Dedup: all six pages of open issues (518 issues, #1883#15270) grepped for serve-publishes-bound-port|bound-port|40733|port race|EADDRINUSE at 07:52Z — one adjacent card, #12884 (five cli e2e files fail on macOS on a clean checkout, port-drift arms), which is a different platform and a different arm; nothing names this queue-build flake.

What happened

The merge-queue build for PR #15073 (parent tip 460134af, run 33848437820, job Test Core (1/6), 07:22–07:47Z) failed on exactly one test and the queue removed the PR at 07:47:48Z:

FAIL integration test/serve-publishes-bound-port.e2e.test.ts
  > #13062 the non-zero half — nothing an ordinary boot publishes may move
  > publishes exactly the port it was asked for when that port is free
AssertionError: expected 40734 to be 40733 // Object.is equality
  ❯ test/serve-publishes-bound-port.e2e.test.ts:361:21   expect(ipc).toBe(asked);
Test Files  1 failed | 243 passed (244)      Tests  1 failed | 2836 passed | 6 expected fail (2843)

PR #15073's diff is scripts/check-role-word.mjs, scripts/check-corpus-claim-drift.mjs and scripts/role-word-baseline.json — nothing in packages/cli, nothing that runs at boot. The seat re-armed the PR once (the single confirmation re-run the landing rules allow); a second drop is treated as real.

The mechanism, read from the test

asked = Number(randomPort()) picks a port that is free at that instant, then bootServe(... '--port', asked) boots the CLI; the assertion holds the published port equal to the requested one. On a shared CI runner (six shards, other packages' suites booting servers in the same minute) another process can take the port between the free-check and the bind, and the CLI then publishes the drifted port — asked + 1 here — which is precisely the "port-drift" behaviour the sibling half of this file tests on purpose. So the "when that port is free" premise is a race, not a fact, and on a busy runner the test measures the runner.

Why it matters more than one red

A queue-build flake does not fail one PR: it drops the PR from the queue, rebuilds every entry behind it, and burns a full Test Core cycle (this one ran 24 minutes) for the whole batch. Two drops in a row of an unrelated PR would look, to the seat driving it, like a real failure.

Not proposed here

The fix belongs to the domain:cli lane: reserve-then-release is the same race; binding the port and handing it to the child, or asserting the published port equals the bound one (the invariant #13062 actually cares about) instead of the requested one, are the shapes to weigh. This card carries no recommendation between them.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions