Repository navigation
ci(lanes): give every three-leg lane the key-credit gate and the empty-subscription handoff - #13608
Conversation
…ery lane The lanes that already ran three legs stopped when their subscription token was empty, even with FALLBACK_CLAUDE_CODE_OAUTH_TOKEN set. They now follow the rule #13590 set: an absent subscription credential hands to the fallback leg, which starts only when the fallback token is set, and the fallback leg's lane record names fallback reason no-key. - pr-run-activity-read.yml: the second call's handed-off output is true on an empty token when the caller runs a third call (fallback-ready), so the caller's subscription-handoff job starts the fallback call; the call ends green instead of failing. This covers every read-runner activity (resolve-conflicts, address-feedback, review-dependency, fix-ci, fix-ci-rung-up, fix-docs, resolve-issue). - pr-verify.yml: check-intent-fallback also runs on the subscription job's empty token with the fallback token set. - maintenance-audit-lane-runs.yml: judge-subscription records a no-key marker for an empty token with the fallback token set. - pr-review-main.yml already followed the rule; unchanged. Refs: #13586 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… every leg The read runner's reuse summary had a key leg and a subscription leg, so on a third call it ran on the empty subscription secret. It now runs on the fallback token there, and writes a lane-outcome record for the leg it ran. upstream-apply-changelog's scrub-probe legs record theirs too. A test now fails any run-claude-cli job with no lane record (lane-id), so every leg's credential, outcome, handoff and durationMs reach lane telemetry; the maintenance role's propose pass is the one listed exception, open on #13586. Refs: #13586 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sweep The read runner's broker-check, which runs no head code, now runs ci-workflows check-key-credit for the first call's key-credit-job. A credit stop inside KEY_CREDIT_WINDOW_HOURS skips the key: the call hands off before any model turn and the caller's next call runs on the subscription. broker-check grants actions: read, so every read-runner caller job does too; the run job keeps contents and pull-requests read. The marker comes from a jobs-API read, never a run job output: the run job's fixed-name "Mark a key credit stop" step runs only on run-claude-cli's handoff-reason, handoff-evidence.sh reads it as the new credit-stop fact, and each first call's handoff job uploads key-credit-stop-<file>-<activity> on it. maintenance-audit-lane-runs.yml gets the same gate: collect reads the key's credit history, a skipped key skips judge, judge-handoffs routes every unit to judge-subscription as a credit-stop handoff (handoff.mjs route-skipped), and uploads the marker after a key leg's credit stop. Refs: #13586 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…redit gate The ci-workflows intake-triage.yml reusable is getting the same check-key-credit gate the review reusable runs, which reads the repository's credit-stop markers with actions: read. A called workflow can hold only what its caller grants, so this caller grants it first; the reusable's gate lands after this merges. Refs: #13586 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-security-review reviewed Security review: PR #13608 (head 9bfdf14)No security issues found. I read every hunk of all 16 changed files in critical-findings: 0 Changes since the last review1. The new
2. The new
Rechecked from the last review1. The
2. The empty subscription token now hands off to the fallback leg
3. The audit lane's skipped-key path
4. The
5. Trust controls: none changed. Nothing touches the trusted-trigger check, the lane token request or broker, the kill switch, or any merge-hold script. Notes
|
|
claude-review reviewed Code review: #13608,
|
The handoff jobs' credit-stop read waits for the jobs listing's step lists, which can lag for minutes, and held up every subscription call behind it. Each caller file now reads it in one key-credit-markers job that no job needs, one read and marker per first call. - .github/artifact-retention.json: an exact row per static marker name (a `*` family never takes a static name), scan none. - write-runner-never-rules.test.sh: the reuse summary's third leg. - handoff-evidence.test.mjs: the key-credit-markers jobs also name HANDOFF_EVIDENCE_LAG. - intake-triage.yml: the caller's actions: read waits for the runner-policy contract to approve it in melodic-software/standards. Refs: #13586 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # .github/actions/resolve-config/callers.test.mjs
Post-merge mutation testingKilled 6, survived 1, timeout 0, no coverage 0, invalid 0, not run 0.
Surviving mutants
The run's summary has the full report. |
…949) Refs: melodic-software/claude-code-plugins#13586 ## Summary This adds `actions: read` to the reviewed `allowedCallerPermissions` of the `intake-triage.yml` contract in `components/runner-policy/policy.json`. After the change, a caller job that grants `actions: read` passes `runner-policy`. ## Fix - [melodic-software/ci-workflows#996](melodic-software/ci-workflows#996) adds the `check-key-credit` gate to `intake-triage.yml`; `pr-review-cli.yml` already has it. The gate lists the repository's credit-stop markers with `actions: read`. A called workflow holds only the permissions its caller job grants, so every caller job must grant `actions: read`. - Until this contract lists that permission, `runner-policy` rejects the claude-code-plugins caller: "reusable workflow caller permissions has unapproved properties". That rejection is the lint-repo failure on [melodic-software/claude-code-plugins#13608](melodic-software/claude-code-plugins#13608). - `actions: read` adds no write access and no token beyond the job's own `GITHUB_TOKEN`. - Callers float on `@main`, so `approvedShas` stays as it is. ## Verification - `node --test components/runner-policy/runner-policy.test.mjs`: 226 tests, 226 pass. ## Related Merge order: 1. This PR, then sync it to the callers. 2. The claude-code-plugins caller grants `actions: read`. That change was taken out of #13608 until this PR syncs, and goes back in afterwards. 3. ci-workflows#996, held with `do-not-merge` until step 2 lands. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Refs: #13586
Summary
The owner asked in #13586 that every lane be "consistent and uniform". This PR gives the lanes that already had all three legs the two rules #13590 and #13592 added:
check-key-creditgate;Fix
Rule (b), an empty subscription token:
pr-run-activity-read.yml(resolve-conflicts, address-feedback, review-dependency, fix-ci, fix-ci-rung-up, fix-docs, resolve-issue)handed-offis also true on an empty token when the caller runs a third call (fallback-ready), so the caller's existing subscription-handoff job starts itpr-verify.ymlcheck-intentcheck-intent-fallbackalso runs oncredential-present == 'false'withfallback-ready == 'true'maintenance-audit-lane-runs.ymljudgeno-keyhandoff marker when the fallback token is set;handoff.mjsacceptsno-keyon that legpr-review-main.ymlIn each case the fallback leg's lane record names fallback reason
no-key. With every token empty, nothing new starts.Per-leg timing:
run-claude-clijob that has noreport-lane-outcomewithlane-id. The one exception is listed: maintenance-measure-skill-editpropose, open on ci(lanes): run every model lane on the same key, subscription and fallback chain #13586.Rule (a), the credit gate:
pr-verify.yml,pr-review-main.ymland ci-workflowspr-review-cli.yml(used by pr-review-hosted and security-hosted) already have it.pr-run-activity-read.yml, all seven activities):broker-check, which runs no head code, runscheck-key-creditfor the first call's newkey-credit-jobinput. A credit-stopped key makes the call hand off before any model turn, and broker-check records the skipped key leg.actions: read, so all 21 read-runner caller jobs now grant it. The run job keeps its contents and pull-requests read pin.Mark a key credit stopstep runs only on run-claude-cli'shandoff-reason.handoff-evidence.shreads that step as a newcredit-stopfact, and each first call's handoff job uploadskey-credit-stop-<file>-<activity>when the fact is true.collectreads the key's credit history. A skipped key skipsjudge.judge-handoffsthen routes every unit tojudge-subscriptionas acredit-stophandoff (handoff.mjs route-skipped). After a key leg's credit stop it uploads the marker.actions: readin the runner-policy contract and syncs here.actions: read. It is not in this PR:runner-policyrefuses that grant until the contract allows it.do-not-merge.key-credit-markersjob per caller file. No job needs that job, so its step-level jobs-API read never delays a handoff. Each static marker name has its own row in.github/artifact-retention.json.Verification
node --testover.github/actions/resolve-config,.github/scripts/{pr-unblock,pr-verify,work-resolve-issue,maintenance-audit-lane-runs,upstream-apply-changelog}and.github/actions/log-api-budget: 3,478 tests, 3,478 pass (plus.github/scripts/intake-triage: 2,128 with resolve-config).fallback-readyhands off. Withoutfallback-readyit hands nothing on and the call still fails.no-keysubscription marker.zizmor --offline: no findings.actionlint: only the existingcache-mode/queuekeys.Related
pr-unblock.yml'sresolve-feedback-threadsis untouched (fix(pr-pipeline): let a human-reply address-feedback round resolve its thread after its own push #13580).Draft: the dispatching session reviews and marks it ready
🤖 Generated with Claude Code