Split 1/2 of #803 (dev-lead timed out at the 2100s action budget doing all of #803 at once). This is the small, high-impact half — a single-function change.
Scope — scripts/canary-rollout.sh, _run_json (~L378-403) ONLY
- Surface the real error. Capture
gh's stderr and include the HTTP status / message in the ::warning:: and final ::error:: lines. Today the retry wrapper prints only "transient failure … after N attempts", hiding whether it's a 403 secondary-rate-limit vs 5xx vs auth. Distinguish these in the output.
- Exponential + jittered backoff. Replace the fixed
CANARY_GH_RETRY_SLEEP linear retry with exponential backoff + jitter; honor Retry-After / x-ratelimit-reset response headers when present; raise the default attempt count. Keep the CANARY_GH_RETRIES / CANARY_GH_RETRY_SLEEP env overrides working.
- Fail closed. A persistent fetch failure must remain a hard error — never a silent empty-but-green gate.
Out of scope (that's #803b)
- Collapsing per-workflow enumeration to a per-repo fetch.
- sync-issues resilience.
Acceptance criteria
- A forced fetch failure prints the real HTTP status/reason, not just "transient".
- Backoff is exponential+jittered;
Retry-After honored; attempts raised.
- Fails closed (no empty-data gate reported as promotable).
- Existing canary-rollout bats stay green; add a case asserting
_run_json surfaces the real error on failure.
Split 1/2 of #803 (dev-lead timed out at the 2100s action budget doing all of #803 at once). This is the small, high-impact half — a single-function change.
Scope —
scripts/canary-rollout.sh,_run_json(~L378-403) ONLYgh's stderr and include the HTTP status / message in the::warning::and final::error::lines. Today the retry wrapper prints only "transient failure … after N attempts", hiding whether it's a 403 secondary-rate-limit vs 5xx vs auth. Distinguish these in the output.CANARY_GH_RETRY_SLEEPlinear retry with exponential backoff + jitter; honorRetry-After/x-ratelimit-resetresponse headers when present; raise the default attempt count. Keep theCANARY_GH_RETRIES/CANARY_GH_RETRY_SLEEPenv overrides working.Out of scope (that's #803b)
Acceptance criteria
Retry-Afterhonored; attempts raised._run_jsonsurfaces the real error on failure.