Repository navigation
perf(pr-verify): read the key's credit history only for a head it judges - #12799
Conversation
check-intent-credit ran before the resolver's no-op exit, so every non-skipped pr-verify run paid its run-list and three job-list reads (api-budget cost=4, run 41591342510) and a VM, including the ~55/h runs that then skip at the resolver (already judged, draft, not one PR). Fold the gate, its carried record and the skipped-leg report into check-intent after the resolver, the trigger gate and the reads hand-on. A skipped key runs no pre-judge setup or judge, writes no "no verdict" failure, and hands on through a skip-key job output, so the subscription job now takes the carried reads instead of reading again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VcupomBPg7kuobwLoNpxEW
ci-workflows#973 (bc62beb) makes check-key-credit read one exact-name artifact instead of run history. check-intent now writes, scans and uploads the gate's `marker` artifact (one-day retention) after a judge step's credit-stop handoff, and the step that carried a record forward is gone. pr-verify's ci-workflows pins move to bc62beb; run-claude-cli changed only in a description there, so its lane.cjs still passes --permission-prompts none (callers.test.mjs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pr-verify.yml now pins run-claude-cli and apply-claude-managed-settings at bc62beb. Between 2476d5d and bc62beb, run-claude-cli changed only one output description in action.yml and apply-claude-managed-settings did not change, so cliArgs, LEG_ENV, CLI_VERSION and MANAGED_SETTINGS still hold; parity.test.mjs fails until the constant moves with the pin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 Code review: PR #12799, perf(pr-verify): read the key's credit history only for a head it judgesNo findings. I read every hunk of all 7 changed files: the changelog fragment, What I checked at head
Not verifiedI had no shell, so I ran no tests, no actionlint and no I could not read ci-workflows at
Closing issueThe PR closes no issue ("No related issue"), so there are no acceptance criteria to check. Prior findingsThe lane's earlier review, at b301732, reported 0 findings. This round adds the SpendSpend goes down: fewer GITHUB_TOKEN reads, and one fewer VM per run that stops at the resolver. Model, turn and billing settings are unchanged. |
|
claude-security-review reviewed Security review: PR #12799 (pr-verify credit gate folded into
|
The marker upload took a computed name, so check-artifact-retention assigned it to the job's computed-name family, pr-verify-* (90 days), and its 1-day retention differed. It now uploads the gate's name, key-credit-stop-pr-verify.yml-check-intent (check-key-credit gate.cjs markerName at bc62beb), under its own 1-day row; the write step runs only while the gate's marker output equals that name, so a gate that names another marker uploads none. The upload's if: now repeats the scan step's if: in parentheses before the clean output, the shape the checker takes as gated by that scan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: GITHUB_TOKEN volume cut #1 (.work volume-cuts 2026-11-03)
Summary
pr-verify ran its credit gate (
check-intent-credit) before the resolver's no-op exit. Every non-skipped run paid for the gate's reads and a VM, including the runs that then stop at the resolver because the head is already judged, the PR is a draft, or there is no single PR. This change folds the gate intocheck-intentafter the resolver, so a no-op run spends nothing on it.This PR was first meant to remove 8 duplicate full judgments seen in the 05:47-06:47Z hour on 2026-11-03. Their run logs show none of them was a duplicate. The judged-head skip (
resolve-pr.mjsjudged()) is unchanged.403 ... until 06:49:01Z), so no verdict was written.fail-i12649).resolve-pr: proceed=true reason=body-edited, after afail-i12658.reason=already-judgedafter 8 calls, and no model ran.Fix
The
check-intent-creditjob is removed. Its gate and report steps now run incheck-intentafter "Hand the reads on":id: credit;They run only when
steps.agree.outcome == 'success', which means the resolver and the trigger gate both passed.The gate reads the credit-stop marker that ci-workflows#973 added (merge commit bc62beb). On the old gate, no-op runs would have filled its newest-3 run window (
MAX_JOB_READS = 3) and hidden a credit stop. The new gate does not scan runs:GET /repos/{repo}/actions/artifacts?name=<marker>. Itsmarkeroutput iskey-credit-stop-pr-verify.yml-check-intent.check-intentruns three new steps: "Write the key's credit-stop marker" (the run id), "Scan the key's credit-stop marker for credentials" (scan-upload) and "Upload the key's credit-stop marker". The upload is namedkey-credit-stop-pr-verify.yml-check-intent, the gate's name, written out so its own 1-day row in.github/artifact-retention.jsonclaims it (a computed name would fall to the job'spr-verify-*row, 90 days). The write step runs only whilesteps.credit.outputs.markerequals that name, so a gate that names another marker uploads none. All three steps arecontinue-on-error. This follows the key job in pr-review-cli.yml at bc62beb.handoff-reason == 'credit-stop'trigger, not upstream'slane-class. That is what the old record step used, and a workflow test banslane-class == 'credit-stop'in anyif.check-intentalready uploads its verdict, and its token keepsactions: read.bc62bebis added to callers.test.mjs's checked launchers, and replay.mjsRUN_CLAUDE_CLI_PINmoves to it.When the key is skipped:
skip-keyjob output hands the judgment tocheck-intent-subscription. That job'sifand its 13fallback-reasonlines readneeds.check-intent.outputs.skip-key.GITHUB_TOKEN (counter A) call change:
cost=4, and ci-workflows#973 measured 2.The old gate missed a credit stop because of its newest-3 window. At 06:41:40 it logged "no run of the newest 3 settles it", while run 41590798290 had recorded a credit stop at 06:39:33. The marker read has no such window, which fixes this.
Verification
.github/scripts/pr-verify/workflow.test.mjs: 39 pass. The tests check that:skip-keyoutput and the subscription gate behave as described.The marker test checks that:
origin-runreference remains;key-credit-stop-pr-verify.yml-plus the gate step'skey-job(gate.cjsmarkerNameat bc62beb), and equalskey-credit-stop-pr-verify.yml-check-intent;ifissteps.credit.outputs.marker == '<that name>'plus the 13-stephandoff-reason == 'credit-stop'chain;ifis the scan step'sifin parentheses, then its clean output;nameis that literal, and the scan and upload use the same path;if-no-files-found: error;continue-on-error;The artifact-upload test now allows the key job a second upload, the marker. The subscription parity test excludes the three marker steps.
.github/scripts/maintenance-reconcile-lost-runs/reconcile.test.mjs: 151 pass. The carried-record row is gone from the credit-skip fixture. reconcile.mjs reads no credit step names.Every node suite that reads pr-verify.yml passes, after merging main at 7cfb456a2d:
babysit-prs pytest (review evidence, verify evidence, verify index, verify rules sync): 753 passed, at the first commit. It was not re-run for the marker change, which touches no Python or verdict names.
scripts/check-artifact-retention.sh --check: 82 upload steps match the table (57 families), after merging main at aef714a.scripts/check-artifact-retention.test.sh: 32 pass, 0 fail.After the retention-row fix: workflow.test.mjs and resolve-config callers.test.mjs, 273 pass, 0 fail.
actionlint (shellcheck on PATH) on pr-verify.yml, with the repository config's
cache-modeignore: clean.Related
.github/actions/check-key-credit/gate.cjsandaction.ymlthere.🤖 Generated with Claude Code
https://claude.ai/code/session_01VcupomBPg7kuobwLoNpxEW