backlog: file #1103, the connscale API port range is unverified past its base - #290
Merged
Merged
Conversation
…its base Observed failing on CI, not hypothesised. PR #289's windows-2022 leg died with [Errno 13] bind on ('127.0.0.1', 62748): [winerror 10013] after 10,770 tests passed, with the step at 27:00 against a 55:00 cap. Not a timeout, and not the throughput SLO already filed as #1101. tests/test_connscale_smoke.py probes ONE free API port via _free_port(), which binds port 0, reads getsockname(), and closes the socket before returning. harness/load/connscale/runner.py:162 then binds api_port + step for every sweep arm. The failing run used 62746, 62747 and 62748; exactly one of the three was ever checked. The symptom hides the cause. A Windows bind onto a held port reports 10013, not the 10048 that reads as a collision, so it presents as an access-permissions problem and invites fixes that touch nothing relevant. The port number is the tell: 62748 is ephemeral, far outside the test's own inbound window [20000, 30000), so it is not the family #1014 reserved. This is #1014's defect one port-family over. #1014 gave the INBOUND block a contiguous reservation, a random anchor, a contiguity assertion at the acquisition site, and a loud failure instead of a silent fallback. None of that reached the API family. The test's comment reasons about the API ports only against the inbound block -- "The sink/API ports stay ephemeral (above the inbound window) and won't hit the block" -- which is true, and silent about the increment range colliding with anything else on the machine. The sink family carries the identical pattern at runner.py:278 and is dormant only because the smoke test passes sink_ports=1. Any profile raising it inherits this item. The fix should cover both families. #1014 removing the flaky(reruns=2) marker is why this is visible at all, and that was correct: its stated intent was that a genuine future collision surface as a RED rather than a masked retry. This is that collision, in the family it did not cover. The fix must not be a re-added retry. Records the mechanism, why the symptom misleads, the dormant sink instance, the shape a guard must take (assert the whole reserved range, not the base), and the separation from #1096 and #1101 with the measured step time. Number allocated via scripts/coord/alloc.ps1, never grepped. Verified: banner invariant holds, backlog hygiene 19 passed, the repo-wide link gate reports 5,359 links across 347 files all resolving.
wshallwshall
enabled auto-merge (squash)
August 8, 2026 16:32
Collaborator
Author
|
Docs-only PR, so this is the repo's blind mode, not its cheap one: the drift guards live in pytest gated on All 89 skips are |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Files BACKLOG #1103. Ledger-only change — one item appended to
docs/BACKLOG.md, no code.Observed, not hypothesised
PR #289's
test (windows-2022, py3.14)leg, run31261658519:The mechanism
_free_port()binds("127.0.0.1", 0), readsgetsockname()[1], and closes the socket in afinallybefore returning. The port is free at the instant it is read and reserved by nothing after.harness/load/connscale/runner.py:162then bindsapi_port + stepfor every sweep arm. The failing run's log carries62746,62747,62748.Exactly one of the three was verified.
Why the symptom hides the cause
A Windows bind onto a port held by another socket reports
10013— access forbidden — not the10048that reads as a collision. Taken at face value it invites running CI elevated, adjusting firewall rules, or blaming the runner image, none of which touch a port-allocation defect.The port number is the tell:
62748is ephemeral, far outside the test's own inbound window[20000, 30000)— so it is not the family #1014 reserved.This is #1014's defect, one port-family over
#1014 gave the inbound block a contiguous reservation, a random anchor to de-correlate concurrent worktrees, contiguity asserted at the acquisition site, and a loud failure rather than a silent fixed fallback. None of that reached the API family.
The test's own comment reasons about the API ports only against the inbound block:
That is true, and silent about the increment range colliding with anything else on the machine. A correct statement about one hazard reading as coverage of a hazard it never mentions is the #1000 shape, in prose.
The sink family carries the identical pattern at
runner.py:278(sink_port + i for i in range(sink_ports)) and is dormant only because the smoke test passessink_ports=1. Any profile raising it inherits this item without touching it.Three distinct failure modes now share this leg
empty_claims_monotonicthroughput SLO620281af)The step here ran 27:00 against a 55:00 cap, which is what rules out the cap; and the failure is a bind before the engine finishes starting, which is what rules out the SLO.
ci.yml's scope note already warns against merging distinct failures on this leg into one cause.Not to be fixed with a retry
#1014 removed
@pytest.mark.flaky(reruns=2)precisely so "a genuine future collision now surfaces as a RED rather than a masked retry". This is that collision, in the family #1014 did not cover — the marker working as intended, not a regression. Re-adding a retry would re-hide the class it was removed to expose.Verification
Number allocated atomically via
scripts/coord/alloc.ps1, never grepped; the ledger gate passed on commit. Banner invariant holds (exactly one status banner).tests/test_backlog_status_check.py: 19 passed. The repo-wide link gate: 5,359 links / 347 files, all resolve.Census note: filed without a row in the re-scoring table, matching #1096 through #1101. The four census lines are recomputed from that table and are unchanged, so they remain accurate about it.