Repository navigation
fix(pr-pipeline): treat an auth failure as a limit stop and carry the lane record on read-lane checks - #10242
Conversation
From 21:35Z to 22:44Z on 2026-10-25 both PR_UNBLOCK secrets returned 401. Each resolve-conflicts run's key leg handed off (scan and report skipped by design), the subscription leg ended class=auth, and its check carried no lane record, because pr-run-activity-read.yml never passed the record to report-check-run. limit-stop.mjs read each as a plain failure and dispatch.mjs retried at once, so #9826's head spent its three runs in 23 minutes and was recorded at the cap before the secrets were re-set. The read workflow now posts the lane record's class and reset, as the write workflow does. limit-stop.mjs treats class=auth as a limit stop that resets fallback-reset hours after the run, still counted toward limit-stops-per-head so a forged record cannot buy unbounded runs, and dispatch.mjs logs a notice naming the class and reset while a head waits. Refs: #9826 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-dead-runs # Conflicts: # .github/scripts/pr-unblock/dispatch.mjs # .github/workflows/pr-run-activity-read.yml
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-review reviewed No findings. I read the full diff ( What I checked
Scope notes
|
|
claude-security-review reviewed No security issues found in this pull request. critical-findings: 0 What I read. All 8 changed files, Trusted paths. None of the changed files match a Forged lane record.
Log injection. The new Spend. The change can cause up to 3 extra lane restarts on a head with a forged or genuine stop. It spends prepaid or subscription usage only, so it is not a hold and not counted as a finding. |
Refs: #9826
Summary
From about 21:35Z to 22:44Z on 2026-10-25,
PR_UNBLOCK_CLAUDE_API_KEYandPR_UNBLOCK_CLAUDE_CODE_OAUTH_TOKENboth returned 401. Each resolve-conflicts run's key leg handed off, so its scan and report jobs were skipped as designed. The subscription leg then endedclass=auth(annotation:resolve-conflicts ended class=auth on PR_UNBLOCK_CLAUDE_CODE_OAUTH_TOKEN api_error_status=401, job 121299868428), andno-model-turn/ "Fail without a result" followed from that.The posted check runs carried no lane record (summary
The activity step failed.):pr-run-activity-read.ymlnever passed the record toreport-check-run.limit-stop.mjstherefore read each check as a plain failure, anddispatch.mjsretried at once. #9826's head ab760e9 spent all three runs between 21:44Z and 22:07Z and was recorded at the cap before the secrets were re-set. #10121 and #10118 went the same way.Fix
pr-run-activity-read.yml: the run job exposes the lane record'sfailure-classandresets-at, and the report job passes them toreport-check-runaslane-classandlane-resets, the same waypr-run-activity-write.ymldoes.limit-stop.mjs:class=authis a limit stop. It names no reset, so it resetslimits.fallback-resethours after the run, and it still counts towardlimit-stops-per-head. NewpendingStopreturns the unreset stop that resets last.dispatch.mjs: while a head waits only on an unreset stop, it logs::notice::#N: head <sha>'s pr-unblock / resolve-conflicts stopped on class=<class>; no resolve-conflicts before <time>. The cap warning now ends with; the last run stopped on class=<class>when the newest run was a stop.limit-stops-per-headtimes. For address-feedback and review-dependency, whose dispatchers do not retry failures, that is up to three restarts where there used to be none. This is the same bounded risk the write lanes already accept.Limitsand resolve-conflicts dispatch text updated.Under this rule, each head would have spent one run during the outage and retried after the reset.
Verification
node --testoverlimit-stop,dispatch,feedback-dispatchanddependency-dispatchtests: 196 pass, 0 fail.resolve-config/callers.test.mjs: 183 pass, 0 fail. It includes a new wiring test for the read workflow's lane record.report-check-runtests: 101 pass, 0 fail.actionlint .github/workflows/pr-run-activity-read.yml: clean.Related
fix-ci-dispatch.mjs(capCount), which does not read lane records. A refused credential still spends a fix-ci head's three runs at once (feat(guardrails): deny a blocking hook row whose dispatcher exits 0 without a verdict #10120, refactor(guardrails): resolve the commit convention from docs conventions source-control.yaml #10134 on 2026-10-25). That change is left for a follow-up, which will need to coordinate with the open fix-ci dispatch branch.🤖 Generated with Claude Code