fix(tools): tell an upstream outage from a failed check - #73
Merged
Merged
Conversation
tools/net.sh retries curl and read-only gh calls on 5xx, 429, timeouts, DNS and refused connections, then exits 8; a 404, a certificate failure or an unrecognised gh error exits 7 at once. fetch.sh, check-updates.sh, land-updates.sh and intake-check.sh go through it, and a checksum or size mismatch in fetch.sh is exit 7. Run 34836792047 failed check / build with curl: (22) ... 500 six times and exit 22 during a GitHub incident, indistinguishable from a checksum failure.
This was referenced Sep 14, 2026
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.
Problem
Run 34836792047,
check / buildon a pull request, 2026-09-14, during a GitHub incident:fetch.shalready retried:--retry 5 --retry-delay 2 --retry-all-errors, about ten seconds. Then it exited 22, which is indistinguishable from a checksum or signature failure, and a manual rerun passed. owfeed's CLI contract separates the two (exit 7: a check failed, never retry; exit 8: upstream outage, safe to retry). The shell here did not.Measurements
curl, against a local stub that answers a chosen status. Same result on curl 8.7.1 (macOS) and curl 8.5.0 (
ubuntu:24.04, the runner's version):%{http_code}curl: (22) The requested URL returned error: 404Failed to connect ... Couldn't connect to serverCould not resolve hostConnection timed out--retry 2on 404--retry 2on 429 / 500 / 503, DNS, refused (--retry-connrefused)--retry 2 --retry-all-errorson 404So under
-fthe exit code cannot tell a 500 from a 404; only-w '%{http_code}'can.--retry-all-errors, whichfetch.shused, re-asks for a 404.gh 2.99.0 exits 1 for everything, so only the text tells an outage from an answer:
release view, 5xx / 429 (stub viagithub.localhost)HTTP 503: <message> (http://api.github.localhost/repos/o/r/releases/latest)gh api, 5xxgh: <message> (HTTP 503)Get "https://api.github.com/...": proxyconnect tcp: dial tcp 127.0.0.1:1: connect: connection refusederror connecting to nonexistent.invalid check your internet connection or https://githubstatus.comrelease not foundno assets match the file patterngh apimissing repo (real API)gh: Not Found (HTTP 404)gh made exactly one request per call in every case; it does not retry.
Design
tools/net.sh, one helper, run as a command (nothing undertools/sources another script):tools/net.sh get <url> <dest>runs curl without--retryand loops itself: 5 attempts, delays 5/10/20/40 s (about 75 s).!! upstream outage: …and, in Actions, an::error title=Upstream outage (exit 8, safe to rerun)::annotation.tools/net.sh gh <args>does the same for read-only gh calls, classifying stderr by the texts measured above. The stderr of a definite failure is passed through verbatim, becausecheck-updates.shcomparesrelease not foundexactly.gh pr createandgh workflow runare not wrapped: a create that timed out after GitHub accepted it would be repeated.Callers:
fetch.shget(artifacts,.sig, manifest)--retry 5 --retry-all-errors, exit 22 for everything, 404 re-askedfetch.shchecksum / manifest size mismatchfetch.shunpinned source archivecheck-updates.shgh release view,gh api …/releases,gh release downloadland-updates.shgh pr list,gh api …/check-runs,gh api …/matching-refsintake-check.shgh release view, manifest curlintake.ymlposts "GitHub or the manifest's host did not answer… you do not need to change anything"update.ymlpublish-dispatch job (gh api,gh run list,gh workflow run)No automatic step-level rerun on exit 8.
pre-buildruns inside owfeed's reusablefeed.yml, and the loop it runs is not idempotent:fetch.shappends todist/staged.txtanddist/sources/staged.txt, so re-running the step after a partial fetch would duplicate rows thatcheck-tree.shandsources.shread. The in-place retries cover a CDN blip; an incident longer than 75 s ends as exit 8 with an annotation that says to rerun. owfeed/owfeed#21 makes owfeed's own CLI consistent with the same split.Tests
New
tools/test-net.sh(stubcurlandghon PATH, no network), added to thetoolsjob inpr.yml. It covers net.shget(200, 404, 500 throughout, 503 then 200, 429, 502, exits 6/7/28/56, certificate 60, the Actions annotation), net.shgh(release not foundverbatim, HTTP 503, cannot connect, HTTP 404, 502 then an answer) andfetch.shend to end (artifact 500/404, checksum mismatch, source archive 404 vs 503).test-check-updates.sh: b0-outage is asked 5 times and reported as an outage, b1-missing once. The fifth run has only outages (a 503 on download plus the 502 on view) and asserts exit 8 with nothing pushed.test-land-updates.sh: gh pr list 502 is asked 5 times, the run exits 8, and a failed git step exits 1.Fails before, passes after. The same tests against the
origin/mainscripts (FETCH=,CHECK_UPDATES=,LAND_UPDATES=overrides):With this branch (and the fixture fix in eb04986), all four
tools/test-*.shprintPASS, anddash -n tools/*.shis clean.RUNBOOK (EN/RU), under "A check is red":
!! upstream outage/ exit 8 → rerun (and what the oldcurl: (22) … 500×6 / exit 22 meant);curl: (22) … 404/ exit 7 → wrong tag or file name.