fix(ci): make a failed release check say what it actually saw #149

Merged
tudor merged 1 commits from fix/release-check-diagnostics into main 2026-09-15 15:09:47 +00:00
Owner

Follow-up to #148. The release identity gate landed, but when it fails it currently tells us almost nothing.

The problem

scripts/ci/release.py swallowed every failure in one except (OSError, ValueError): pass. A timed-out run said only that the expected release never appeared — it could not distinguish:

  • the staging proxy rejecting the request,
  • the release endpoint being unavailable,
  • containers still serving an older SHA or build ID.

The public staging proxy also answers HTTP 403 to urllib's default user agent while /release.json is healthy, which presents exactly like a deployment that never arrived.

The changes

  • The poller identifies itself as SchoolCompare-Release-Check/1.0 and sends Accept: application/json.
  • Each distinct observation is printed once — HTTP status, connection-failure type, invalid JSON, or the release identities actually reported — so a retry loop does not flood the log.
  • The timeout error carries both the identity it wanted and the last observation.
  • Logging stays tight: only sha/build_id values that validate as 40/32 hex (or development) are echoed; response bodies and the base URL never are. HTTPError is closed rather than leaked.
  • docs/DEPLOY.md records the user-agent rationale and how to read a failed verification, with an explicit note not to bypass the gate to unblock a deploy.

Verification

  • 228 passed across backend/tests scripts/ci/tests pipeline/tests, run on this branch rebased onto current main.
  • New tests cover the client headers, the retry-until-match path, single-reporting of repeated observations, and — parametrised over 403 / connection failure / timeout / non-JSON / non-object / malformed identity — that neither the log nor the raised error leaks the response body or the base URL.

Not proven locally: the actual staging proxy behaviour. That needs a staging run; this change is what makes the next failure legible.

🤖 Generated with Claude Code

Follow-up to #148. The release identity gate landed, but when it fails it currently tells us almost nothing. ## The problem `scripts/ci/release.py` swallowed every failure in one `except (OSError, ValueError): pass`. A timed-out run said only that the expected release never appeared — it could not distinguish: - the staging proxy rejecting the request, - the release endpoint being unavailable, - containers still serving an older SHA or build ID. The public staging proxy also answers **HTTP 403 to urllib's default user agent** while `/release.json` is healthy, which presents exactly like a deployment that never arrived. ## The changes - The poller identifies itself as `SchoolCompare-Release-Check/1.0` and sends `Accept: application/json`. - Each *distinct* observation is printed once — HTTP status, connection-failure type, invalid JSON, or the release identities actually reported — so a retry loop does not flood the log. - The timeout error carries both the identity it wanted and the last observation. - Logging stays tight: only `sha`/`build_id` values that validate as 40/32 hex (or `development`) are echoed; response bodies and the base URL never are. `HTTPError` is closed rather than leaked. - `docs/DEPLOY.md` records the user-agent rationale and how to read a failed verification, with an explicit note not to bypass the gate to unblock a deploy. ## Verification - `228 passed` across `backend/tests scripts/ci/tests pipeline/tests`, run on this branch rebased onto current `main`. - New tests cover the client headers, the retry-until-match path, single-reporting of repeated observations, and — parametrised over 403 / connection failure / timeout / non-JSON / non-object / malformed identity — that neither the log nor the raised error leaks the response body or the base URL. Not proven locally: the actual staging proxy behaviour. That needs a staging run; this change is what makes the next failure legible. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tudor added 1 commit 2026-09-15 15:02:31 +00:00
fix(ci): make a failed release check say what it actually saw
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m11s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 17s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m17s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 1m4s
64ae71d7ab
The staging poller swallowed every failure identically, so a run that
timed out told us only that the expected release never appeared — not
whether the proxy refused us, the endpoint was down, or the containers
were still serving an older build. The public staging proxy also answers
403 to urllib's default user agent while the release endpoint is healthy,
which looked exactly like a deployment that never arrived.

Identify the poller, and report each distinct observation once: HTTP
status, connection failure type, invalid JSON, or the release identities
actually reported. The timeout error carries the last observation and the
identity it wanted. Responses and the base URL stay out of the logs —
only validated sha/build_id fields are echoed back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

🤖 AI Code Review (Claude Code)

This PR improves the release-verification poller in scripts/ci/release.py with structured, rate-limited logging of HTTP/connection failures and observed release identities, adds a distinguishing User-Agent header (to work around a proxy 403 on the default urllib UA), and includes the last observation in the timeout error message. The accompanying tests are thorough, including explicit checks that raw response bodies, secret hostnames, and URLs are never leaked into logs or error messages, and the docs update accurately describes the new debugging behavior.

✅ No issues found.

## 🤖 AI Code Review (Claude Code) This PR improves the release-verification poller in scripts/ci/release.py with structured, rate-limited logging of HTTP/connection failures and observed release identities, adds a distinguishing User-Agent header (to work around a proxy 403 on the default urllib UA), and includes the last observation in the timeout error message. The accompanying tests are thorough, including explicit checks that raw response bodies, secret hostnames, and URLs are never leaked into logs or error messages, and the docs update accurately describes the new debugging behavior. ✅ No issues found.
tudor merged commit dfce308f1f into main 2026-09-15 15:09:47 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tudor/school_compare#149