fix(ci-queue-watch): fail scheduled runs on a missing FLEET_READ_PAT - #780
fix(ci-queue-watch): fail scheduled runs on a missing FLEET_READ_PAT#780claude[bot] wants to merge 1 commit into
Conversation
The watchdog's "no token -> warn, exit 0" rule was applied unconditionally, including on `schedule`. That let it report green for 10 straight runs -- twice while the fleet was 40 hours into a total ARC outage -- because FLEET_READ_PAT was unset and it silently skipped rather than looking. The reasoning behind the soft path is correct on pull_request/workflow_dispatch (a fork PR or contributor without org secrets is an environmental gap, not an outage) but wrong on schedule, which has no legitimate transient reason to lack its token. token_gate() now branches on the trigger: schedule with no token is a hard failure (exit 1, ::error::); every other trigger keeps warning and exiting 0. The decision moved out of embedded workflow bash into ci_queue_watch.py's `--token-gate` mode so it is unit-testable the same way the rest of the script already is. Also verified the other half of the same question: with a token present and a pool genuinely STALLED, does a scheduled run already fail? Yes -- `--fail-on-stall` plus the pipefailed `run:` step already propagates the non-zero exit; added an end-to-end test (fake GitHub API over a local HTTP server) to prove it rather than assume it, since that path was otherwise unverified. Both new test classes were mutation-verified: reverting token_gate() to the pre-fix always-warn behavior fails only test_scheduled_run_with_no_token_is_a_hard_failure; reverting --fail-on-stall to always return 0 fails only test_stalled_pool_with_token_present_fails. All 21 self-tests pass with the fix in place; actionlint is clean on the workflow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
izzywdev
left a comment
There was a problem hiding this comment.
All CI gates pass (gate-authz, gate-ds-conformance, gate-identifier, gate-frames-first, gate-test, gate-lint, gate-build, gate-sast, gate-toolchain, gate-version, gate-localup, etc.). Approving per governance policy.
|
Closing as superseded by #797 — owner decision. Three PRs (#780, #797, #802) rewrite the same token-gate step in What this PR did well, recorded so it isn't lost:
Why #797 was chosen over it:
The residual risk in #797 is noted: if that job's No work is lost — the defect is fixed by #797. Generated by Claude Code |
Summary
The watchdog's "no token -> warn, exit 0" rule applied unconditionally, including on
schedule. It has run 10 times, every run green, and observed nothing -- becauseFLEET_READ_PATis unset and the token check takes its soft path regardless of trigger. It reported green twice today (07:20Z, 07:57Z) while the fleet was 40 hours into a total ARC outage: exactly the failure pattern this watchdog exists to detect, reproduced inside the detector.The soft-path reasoning is correct on
pull_request/workflow_dispatch(a fork PR or contributor without org secrets is an environmental gap, not an outage) but wrong onschedule, which has no legitimate transient reason to lack its token: either the secret is configured, or the tool is permanently inert.token_gate()inscripts/ci_queue_watch.pynow branches on the trigger:schedule+ no token -> hard failure,::error::namingFLEET_READ_PAT, what it needs to be, and where to set it.pull_request/workflow_dispatch+ no token -> unchanged:::warning::, exit 0.The decision moved out of embedded workflow bash into a new
--token-gateCLI mode on the script (readsFLEET_READ_PAT/GITHUB_EVENT_NAME, writesok=to$GITHUB_OUTPUT) so it's unit-testable the same way the rest of the script already is, instead of only exercised live by cron.The other half, checked per the ask: with a token present and a pool genuinely
STALLED, does a scheduled run already fail, or does it report-and-exit-0 too? Readmain():--fail-on-stallreturns exit 1 on a stall, theObserve the fleet CI queuestep pipes throughteeunderset -o pipefail(and the Actions default shell is alreadybash -eo pipefail), so the non-zero exit already propagates and fails the step/job. This path was already correct -- it just had zero test coverage, so I added an end-to-end test (fake GitHub API on a local HTTP server, real CLI invocation) to prove it rather than leave it assumed.Tests
Both new test classes were mutation-verified per the ask -- restore the pre-fix behavior, confirm the new test (and only the new test) fails:
token_gate()back to unconditional warn/exit-0 -> onlytest_scheduled_run_with_no_token_is_a_hard_failurefailed; the siblingpull_request/workflow_dispatchtests, and all 19 other pre-existing tests, still passed.--fail-on-stall's return to always0-> onlytest_stalled_pool_with_token_present_failsfailed; everything else, including the new token-gate tests, still passed.python3 -m unittest discover -s scripts/__tests__ -p 'test_ci_queue_watch*.py'-> 21 passed with the fix in place (up from the prior 12).Validation run
actionlint .github/workflows/ci-queue-watch.yml-> clean (0 findings; a full-repoactionlintrun does surface 65 pre-existing shellcheck warnings in unrelated workflow files, none touched by this PR).python3 -m py_compile scripts/ci_queue_watch.py-> OK.actions/checkout/actions/setup-pythonSHA pins; no newuses:introduced).FuzeFront's own hosted runners work --
release.ymlsucceeded twice today (32623499635,32623431741, both 2026-08-23 ~06:38Z) -- so this PR's checks can actually conclude, unlike much of the fleet during the outage this fix is about.Test plan
python3 -m unittest discover -s scripts/__tests__ -p 'test_ci_queue_watch*.py'-- 21/21 passactionlint .github/workflows/ci-queue-watch.yml-- cleanmasterpost-merge (next*/15 * * * *tick) -- not verifiable pre-mergeCo-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01GaPa3JgrVNtWrGvqQEAEqv
Generated by Claude Code