You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
No test makes a served-digest read fail with a URLError that has no HTTP status, so release.yml's except can be narrowed with the suite green #286
Found by lane openRepoTools-2's independent re-check of #284 (PR 3b of #228), its comment 6284132726, NIT 4. Lane 2's own weighting: "Re-run failed jobs" recovers from it.
Line numbers are .github/workflows/release.yml at 7376b34, as lane 2 gives them. That file is blob 9a27e2e at 7376b34, at #284's head 2ff7094 and in tree 7ad2bbe (the tree main holds once #284 lands), so the lines are #284's and, once it lands, main's. test :N is tests/test_release_workflow.py at 2ff7094 (blob 8273f40, also in 7ad2bbe).
What happens
After each upload, the job reads the index's JSON up to 20 times, 15 seconds apart. A failed read is caught by except (urllib.error.URLError, TimeoutError, ConnectionError) as error: (:1223 in the testpypi job, :1723 in the pypi job) and retried, unless its code is a client error other than 404.
urllib raises a URLError with no status when it cannot connect, as for a refused connection or a DNS failure. No test makes a read fail that way: SERVED_CASES (test :3270-3285) answer with a status (200, 403, 404 or 503) or with DROPPED, a connection closed with no response (test :3130). That raises http.client.RemoteDisconnected, which urllib does not wrap (lane 2's question 4), so only the ConnectionError member is exercised.
Where
release.yml:1223-1227 and :1723-1727, two copies of one script; the fake index is FakeIndex (test :3148-3197).
How it was found
Lane 2's re-check at 7376b34: narrowing the except at :1223 and :1723 to (HTTPError, TimeoutError, ConnectionError) passes the suite (its measurement).
The fix
Lane 2 proposed none; its NIT names the gap.
What a fix has to settle (nothing here is decided):
how a case makes a read fail with a URLError and no status while the suite stays offline, with the fake index the only server (a port nobody listens on, for example);
whether a read that times out is added with it: no case makes one, since the handler answers or closes at once (test :3159-3177).
CLAIMED — lane openRepoTools-2, session 202778d2-0e63-4478-9c95-fdde314b0524@Eagle, 2026-10-20T23:00:14Z, for #286
Logged in lanes/log/openRepoTools-2.md at b592499a6fa61eb2a04ae133110b9c6068f86169.
The three reads (lane-collision-protocol Rule 1):
1. existing `CLAIMED —` comments on opensoft/openRepoTools#286:
none
2. `gh pr list --repo opensoft/openRepoTools --state all --search "#286"`, kept where the row or its body names `#286`:
284 PR 3's re-check survivors are killed: tests/test_release_workflow.py runs the fetch, pipx, approval, tag, ref, clean, stamp, dist and digest steps instead of reading them, and release.yml changes only in comments (#228, PR 3b) 006-release-pypi-pr3b MERGED
3. `git ls-remote --heads git@github.com:opensoft/openRepoTools` branches naming `286` as a whole token:
none
Lane openRepoTools-2, 2026-10-21T02:2xZ: #286 is done, on a branch only. It is branch test/286-served-read-urlerror-lane2 at 35b18b2, one commit on main a42946e, to be cherry-picked into openRepoTools-code after v1.1.0 is tagged.
The new case is a-refused-connection-then-served, run for both upload jobs. The fake index redirects the read to a port nobody listens on, so urlopen raises a URLError with no status. The test also requires the step's output to carry urlopen error.
The proof: with both excepts narrowed to (HTTPError, TimeoutError, ConnectionError), the two new cases fail with an uncaught URLError. Without the narrowing, 24 pass.
-k test_release_workflow passes 501.
Not covered: a timed-out read. The step's urlopen(timeout=30) waits a real 30 s, which the fake clock does not shorten.
Lane openRepoTools-2, 2026-10-21T11:2xZ: #286 has a second commit, ae3e8e0, on the same branch. It covers a read that times out. No case reached that member of the served check's except before.
How the case works:
The fake index now takes a request and answers nothing.
The timeout of the step's first connection is cut to 0.5 s, so the step's own urlopen raises a bare TimeoutError through a real socket.
release.yml is unchanged.
The new case,a-timed-out-read-then-served, runs for both upload jobs. It also requires the step to print "did not answer yet (timed out)", so a dropped connection cannot pass for a timeout.
The mutant proof: with TimeoutError removed from the except at release.yml:1223 and :1723, the 2 new cases fail and the 24 other served-check cases pass.
Below Python 3.10 the case skips, because there a timed-out read raises socket.timeout, which is not a TimeoutError.
Results:
-k test_release_workflow on the branch: 503 passed.
Lane openRepoTools-2, 2026-10-21T16:2xZ: the final review of #286 is READY, with no MUST and no SHOULD. It was an opus pass, on Brett Heap's word.
Head:4a83bac. It holds the branch's own commits 35b18b2 and ae3e8e0, plus a merge of main 50d05d4 that carries only main's delta.
The timed-out read (ae3e8e0) holds.
With TimeoutError dropped from both excepts, exactly the two new cases fail, with an uncaught TimeoutError: timed out. The other 24 served-check cases pass.
With the served reads' timeout removed, both new cases fail at their "(timed out)" assertion. So the case also guards the read's timeout.
Each new case takes under a second, and the 3.10 skip cannot reach the package job's no-skip check.
Activity
PR 3's re-check survivors are killed: tests/test_release_workflow.py …
brettheap commentedon Oct 20, 2026
CLAIMED — lane openRepoTools-2, session 202778d2-0e63-4478-9c95-fdde314b0524@Eagle, 2026-10-20T23:00:14Z, for #286
Logged in
lanes/log/openRepoTools-2.mdatb592499a6fa61eb2a04ae133110b9c6068f86169.The three reads (lane-collision-protocol Rule 1):
brettheap commentedon Oct 21, 2026
Lane openRepoTools-2, 2026-10-21T02:2xZ: #286 is done, on a branch only. It is branch
test/286-served-read-urlerror-lane2at35b18b2, one commit on maina42946e, to be cherry-picked into openRepoTools-code after v1.1.0 is tagged.a-refused-connection-then-served, run for both upload jobs. The fake index redirects the read to a port nobody listens on, sourlopenraises aURLErrorwith no status. The test also requires the step's output to carryurlopen error.(HTTPError, TimeoutError, ConnectionError), the two new cases fail with an uncaughtURLError. Without the narrowing, 24 pass.-k test_release_workflowpasses 501.urlopen(timeout=30)waits a real 30 s, which the fake clock does not shorten.Lane: openRepoTools-2
tests/test_release_workflow.py makes a served-digest read time out an…
brettheap commentedon Oct 21, 2026
Lane openRepoTools-2, 2026-10-21T11:2xZ: #286 has a second commit,
ae3e8e0, on the same branch. It covers a read that times out. No case reached that member of the served check's except before.urlopenraises a bareTimeoutErrorthrough a real socket.release.ymlis unchanged.a-timed-out-read-then-served, runs for both upload jobs. It also requires the step to print "did not answer yet (timed out)", so a dropped connection cannot pass for a timeout.TimeoutErrorremoved from the except atrelease.yml:1223and:1723, the 2 new cases fail and the 24 other served-check cases pass.socket.timeout, which is not aTimeoutError.-k test_release_workflowon the branch: 503 passed.packagejob fails onubuntu-latestfor every branch (Releases: annotated tags, release/vX.Y branches, and openrepotools on TestPyPI and PyPI from v1.1.0 #228 6314613685).It is still a branch only, to be cherry-picked into openRepoTools-code after v1.1.0 is tagged.
Lane: openRepoTools-2
Merge main (50d05d4, with #296's ubuntu-24.04 pin) into test/286-serv…
brettheap commentedon Oct 21, 2026
Lane openRepoTools-2, 2026-10-21T16:2xZ: the final review of #286 is READY, with no MUST and no SHOULD. It was an opus pass, on Brett Heap's word.
4a83bac. It holds the branch's own commits35b18b2andae3e8e0, plus a merge of main50d05d4that carries only main's delta.ae3e8e0) holds.TimeoutErrordropped from both excepts, exactly the two new cases fail, with an uncaughtTimeoutError: timed out. The other 24 served-check cases pass.(OSError, http.client.HTTPException). The mutant in this issue's earlier note then no longer applies as written. The behaviour still holds, becauseOSErrorcatchesTimeoutError, and the combined run passes.4a83bachas all four jobs green.Lane: openRepoTools-2