From 899c0ecfa1eb2fa11e9dec2f9a70fac756118934 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Thu, 5 Nov 2026 16:00:43 -0500 Subject: [PATCH 1/2] ci(lanes): hand an empty subscription token to the fallback leg intake-triage.yml and pr-review-cli.yml ran their fallback leg only on the subscription leg's handoff, so an empty subscription token stopped the lane even with FALLBACK_CLAUDE_CODE_OAUTH_TOKEN set. The fallback job now also starts when the subscription job's credential-present is false and its fallback-ready is true, the same rule an empty key follows to the subscription leg, and its lane record names fallback reason no-key. With every token empty nothing new starts. Refs: melodic-software/claude-code-plugins#13586 Co-Authored-By: Claude Opus 5.5 --- .github/scripts/intake-triage-legs.test.cjs | 14 +++++++++++--- .github/scripts/pr-review-cli.test.cjs | 8 +++++++- .github/workflows/intake-triage.yml | 9 +++++++-- .github/workflows/pr-review-cli.yml | 9 +++++++-- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.github/scripts/intake-triage-legs.test.cjs b/.github/scripts/intake-triage-legs.test.cjs index 5c75287c..52661a75 100644 --- a/.github/scripts/intake-triage-legs.test.cjs +++ b/.github/scripts/intake-triage-legs.test.cjs @@ -118,7 +118,7 @@ test("every model job tells its launcher whether the fallback token is set, neve } }); -test("the fallback job runs on a fixed GitHub-hosted label only after the subscription job hands off", () => { +test("the fallback job runs on a fixed GitHub-hosted label only after the subscription job hands off or finds its token empty with the fallback token set", () => { assert.equal(fallback.name, "claude-intake-triage-fallback"); assert.equal(fallback["runs-on"], "ubuntu-24.04"); assert.deepEqual(fallback.needs, ["claude", "subscription"]); @@ -132,7 +132,10 @@ test("the fallback job runs on a fixed GitHub-hosted label only after the subscr JSON.stringify(handoff), ); } - // An empty subscription token is not a handoff: no fallback. + // An empty subscription token hands on as an empty key does, but only to + // a fallback token that is set (claude-code-plugins#13586). + assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "true" }), true); + assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "false" }), false); assert.equal(starts({ handoff: "", "credential-present": "false" }), false); assert.doesNotMatch(fallback.if, /always\(\)|failure\(\)|cancelled\(\)/u); for (const step of fallback.steps) { @@ -149,7 +152,8 @@ test("the fallback job runs on a fixed GitHub-hosted label only after the subscr const FALLBACK_LEG_REASON = `\${{ needs.subscription.outputs.handoff-reason == 'limit-stop' && 'limit-stop' || ` + "needs.subscription.outputs.handoff-reason == 'credit-stop' && 'credit-stop' || " + - "needs.subscription.outputs.handoff-reason == 'auth' && 'auth' || '' }}"; + "needs.subscription.outputs.handoff-reason == 'auth' && 'auth' || " + + "needs.subscription.outputs.credential-present == 'false' && 'no-key' || '' }}"; test("the fallback job repeats the subscription job's steps but for the credential and the fallback reason", () => { const strip = (steps, secret, input) => @@ -189,6 +193,10 @@ test("the fallback job repeats the subscription job's steps but for the credenti }); for (const known of ["limit-stop", "credit-stop", "auth"]) assert.equal(reason(known), known); + assert.equal( + evaluate(value, { needs: { subscription: { outputs: { "handoff-reason": "", "credential-present": "false" } } } }), + "no-key", + ); for (const forged of ["", "no-key", "Limit-Stop", "limit-stop\n::error::x"]) { assert.equal(reason(forged), "", JSON.stringify(forged)); } diff --git a/.github/scripts/pr-review-cli.test.cjs b/.github/scripts/pr-review-cli.test.cjs index 76d210a6..91478683 100644 --- a/.github/scripts/pr-review-cli.test.cjs +++ b/.github/scripts/pr-review-cli.test.cjs @@ -174,6 +174,11 @@ test("the fallback job starts only after the subscription job succeeded and hand for (const result of ["failure", "cancelled", "skipped"]) { assert.equal(starts({ handoff: "true" }, result), false, result); } + // An empty subscription token hands on as an empty key does, but only to a + // fallback token that is set (claude-code-plugins#13586). + assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "true" }), true); + assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "false" }), false); + assert.equal(starts({ handoff: "", "credential-present": "" , "fallback-ready": "true" }), false); // A fork, a draft or Dependabot never reaches it either. assert.equal( Boolean( @@ -198,7 +203,8 @@ test("the fallback job starts only after the subscription job succeeded and hand const FALLBACK_LEG_REASON = `\${{ needs.review-subscription.outputs.handoff-reason == 'limit-stop' && 'limit-stop' || ` + "needs.review-subscription.outputs.handoff-reason == 'credit-stop' && 'credit-stop' || " + - "needs.review-subscription.outputs.handoff-reason == 'auth' && 'auth' || '' }}"; + "needs.review-subscription.outputs.handoff-reason == 'auth' && 'auth' || " + + "needs.review-subscription.outputs.credential-present == 'false' && 'no-key' || '' }}"; test("the fallback job repeats the subscription job's steps but for the credential and the fallback reason", () => { const strip = (steps, secret, input) => diff --git a/.github/workflows/intake-triage.yml b/.github/workflows/intake-triage.yml index d30eba77..c8da218d 100644 --- a/.github/workflows/intake-triage.yml +++ b/.github/workflows/intake-triage.yml @@ -379,6 +379,7 @@ jobs: handoff-reason: ${{ steps.claude.outputs.handoff-reason }} credential: ${{ steps.claude.outputs.credential }} credential-present: ${{ steps.credential.outputs.present }} + fallback-ready: ${{ steps.credential.outputs.fallback-ready }} triage-failed: ${{ steps.review-outcome.outputs.review-failed }} failure-class: ${{ steps.claude.outputs.lane-class || steps.review-outcome.outputs.failure-class }} result-subtype: ${{ steps.extract.outputs.result-subtype }} @@ -1132,6 +1133,7 @@ jobs: handoff-reason: ${{ steps.claude.outputs.handoff-reason }} credential: ${{ steps.claude.outputs.credential }} credential-present: ${{ steps.credential.outputs.present }} + fallback-ready: ${{ steps.credential.outputs.fallback-ready }} triage-failed: ${{ steps.review-outcome.outputs.review-failed }} failure-class: ${{ steps.claude.outputs.lane-class || steps.review-outcome.outputs.failure-class }} result-subtype: ${{ steps.extract.outputs.result-subtype }} @@ -1870,7 +1872,9 @@ jobs: fallback: name: claude-intake-triage-fallback needs: [claude, subscription] - if: needs.subscription.outputs.handoff == 'true' + if: >- + needs.subscription.outputs.handoff == 'true' + || needs.subscription.outputs.credential-present == 'false' && needs.subscription.outputs.fallback-ready == 'true' runs-on: ubuntu-24.04 timeout-minutes: 19 # The model's job reads and never writes: the token can read the issue @@ -1885,6 +1889,7 @@ jobs: handoff-reason: ${{ steps.claude.outputs.handoff-reason }} credential: ${{ steps.claude.outputs.credential }} credential-present: ${{ steps.credential.outputs.present }} + fallback-ready: ${{ steps.credential.outputs.fallback-ready }} triage-failed: ${{ steps.review-outcome.outputs.review-failed }} failure-class: ${{ steps.claude.outputs.lane-class || steps.review-outcome.outputs.failure-class }} result-subtype: ${{ steps.extract.outputs.result-subtype }} @@ -2495,7 +2500,7 @@ jobs: known-failure-class: ${{ steps.claude.outputs.lane-class }} handoff: ${{ steps.claude.outputs.handoff }} # Why this job ran, for this leg's lane record. - fallback-reason: ${{ needs.subscription.outputs.handoff-reason == 'limit-stop' && 'limit-stop' || needs.subscription.outputs.handoff-reason == 'credit-stop' && 'credit-stop' || needs.subscription.outputs.handoff-reason == 'auth' && 'auth' || '' }} + fallback-reason: ${{ needs.subscription.outputs.handoff-reason == 'limit-stop' && 'limit-stop' || needs.subscription.outputs.handoff-reason == 'credit-stop' && 'credit-stop' || needs.subscription.outputs.handoff-reason == 'auth' && 'auth' || needs.subscription.outputs.credential-present == 'false' && 'no-key' || '' }} # After the outcome step: its timeout check reads the clock when it # runs, so time spent here must not count against a failed leg. diff --git a/.github/workflows/pr-review-cli.yml b/.github/workflows/pr-review-cli.yml index bfbe53db..86131b9d 100644 --- a/.github/workflows/pr-review-cli.yml +++ b/.github/workflows/pr-review-cli.yml @@ -502,6 +502,7 @@ jobs: handoff-reason: ${{ steps.claude-4.outputs.handoff-reason || steps.claude-3.outputs.handoff-reason || steps.claude-2.outputs.handoff-reason || steps.claude.outputs.handoff-reason }} credential: ${{ steps.claude.outputs.credential }} credential-present: ${{ steps.credential.outputs.present }} + fallback-ready: ${{ steps.credential.outputs.fallback-ready }} review-failed: ${{ steps.review-outcome.outputs.review-failed }} failure-class: ${{ steps.claude-4.outputs.lane-class || steps.claude-3.outputs.lane-class || steps.claude-2.outputs.lane-class || steps.claude.outputs.lane-class || steps.review-outcome.outputs.failure-class || ((steps.isolate.outcome == 'failure' || steps.isolate.outcome == 'cancelled') && 'install-failed') || '' }} verdict: ${{ steps.extract.outputs.verdict }} @@ -2620,6 +2621,7 @@ jobs: handoff-reason: ${{ steps.claude-4.outputs.handoff-reason || steps.claude-3.outputs.handoff-reason || steps.claude-2.outputs.handoff-reason || steps.claude.outputs.handoff-reason }} credential: ${{ steps.claude.outputs.credential }} credential-present: ${{ steps.credential.outputs.present }} + fallback-ready: ${{ steps.credential.outputs.fallback-ready }} review-failed: ${{ steps.review-outcome.outputs.review-failed }} failure-class: ${{ steps.claude-4.outputs.lane-class || steps.claude-3.outputs.lane-class || steps.claude-2.outputs.lane-class || steps.claude.outputs.lane-class || steps.review-outcome.outputs.failure-class || ((steps.isolate.outcome == 'failure' || steps.isolate.outcome == 'cancelled') && 'install-failed') || '' }} verdict: ${{ steps.extract.outputs.verdict }} @@ -4683,7 +4685,9 @@ jobs: timeout-minutes: ${{ inputs.lane == 'security' && 117 || 109 }} if: >- needs.review-subscription.result == 'success' - && needs.review-subscription.outputs.handoff == 'true' + && (needs.review-subscription.outputs.handoff == 'true' + || needs.review-subscription.outputs.credential-present == 'false' + && needs.review-subscription.outputs.fallback-ready == 'true') && !cancelled() && github.event_name == 'pull_request' @@ -4710,6 +4714,7 @@ jobs: handoff-reason: ${{ steps.claude-4.outputs.handoff-reason || steps.claude-3.outputs.handoff-reason || steps.claude-2.outputs.handoff-reason || steps.claude.outputs.handoff-reason }} credential: ${{ steps.claude.outputs.credential }} credential-present: ${{ steps.credential.outputs.present }} + fallback-ready: ${{ steps.credential.outputs.fallback-ready }} review-failed: ${{ steps.review-outcome.outputs.review-failed }} failure-class: ${{ steps.claude-4.outputs.lane-class || steps.claude-3.outputs.lane-class || steps.claude-2.outputs.lane-class || steps.claude.outputs.lane-class || steps.review-outcome.outputs.failure-class || ((steps.isolate.outcome == 'failure' || steps.isolate.outcome == 'cancelled') && 'install-failed') || '' }} verdict: ${{ steps.extract.outputs.verdict }} @@ -6699,7 +6704,7 @@ jobs: known-failure-class: ${{ steps.claude-4.outputs.lane-class || steps.claude-3.outputs.lane-class || steps.claude-2.outputs.lane-class || steps.claude.outputs.lane-class }} handoff: ${{ steps.claude-4.outputs.handoff || steps.claude-3.outputs.handoff || steps.claude-2.outputs.handoff || steps.claude.outputs.handoff }} # Why this job ran, for this leg's lane record. - fallback-reason: ${{ needs.review-subscription.outputs.handoff-reason == 'limit-stop' && 'limit-stop' || needs.review-subscription.outputs.handoff-reason == 'credit-stop' && 'credit-stop' || needs.review-subscription.outputs.handoff-reason == 'auth' && 'auth' || '' }} + fallback-reason: ${{ needs.review-subscription.outputs.handoff-reason == 'limit-stop' && 'limit-stop' || needs.review-subscription.outputs.handoff-reason == 'credit-stop' && 'credit-stop' || needs.review-subscription.outputs.handoff-reason == 'auth' && 'auth' || needs.review-subscription.outputs.credential-present == 'false' && 'no-key' || '' }} # After the outcome step: its timeout check reads the clock when it # runs, so time spent here must not count against a failed leg. From 422abd9f625bbdb38fc79944992f9dc26f0cc7e5 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:27:20 -0500 Subject: [PATCH 2/2] style(lanes): format the leg tests with the repository's biome Refs: melodic-software/claude-code-plugins#13586 Co-Authored-By: Claude Opus 5.5 --- .github/scripts/intake-triage-legs.test.cjs | 26 ++++++++++++++++++--- .github/scripts/pr-review-cli.test.cjs | 23 +++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/.github/scripts/intake-triage-legs.test.cjs b/.github/scripts/intake-triage-legs.test.cjs index 52661a75..0dfdabf1 100644 --- a/.github/scripts/intake-triage-legs.test.cjs +++ b/.github/scripts/intake-triage-legs.test.cjs @@ -134,8 +134,22 @@ test("the fallback job runs on a fixed GitHub-hosted label only after the subscr } // An empty subscription token hands on as an empty key does, but only to // a fallback token that is set (claude-code-plugins#13586). - assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "true" }), true); - assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "false" }), false); + assert.equal( + starts({ + handoff: "", + "credential-present": "false", + "fallback-ready": "true", + }), + true, + ); + assert.equal( + starts({ + handoff: "", + "credential-present": "false", + "fallback-ready": "false", + }), + false, + ); assert.equal(starts({ handoff: "", "credential-present": "false" }), false); assert.doesNotMatch(fallback.if, /always\(\)|failure\(\)|cancelled\(\)/u); for (const step of fallback.steps) { @@ -194,7 +208,13 @@ test("the fallback job repeats the subscription job's steps but for the credenti for (const known of ["limit-stop", "credit-stop", "auth"]) assert.equal(reason(known), known); assert.equal( - evaluate(value, { needs: { subscription: { outputs: { "handoff-reason": "", "credential-present": "false" } } } }), + evaluate(value, { + needs: { + subscription: { + outputs: { "handoff-reason": "", "credential-present": "false" }, + }, + }, + }), "no-key", ); for (const forged of ["", "no-key", "Limit-Stop", "limit-stop\n::error::x"]) { diff --git a/.github/scripts/pr-review-cli.test.cjs b/.github/scripts/pr-review-cli.test.cjs index 91478683..2002abbf 100644 --- a/.github/scripts/pr-review-cli.test.cjs +++ b/.github/scripts/pr-review-cli.test.cjs @@ -176,9 +176,26 @@ test("the fallback job starts only after the subscription job succeeded and hand } // An empty subscription token hands on as an empty key does, but only to a // fallback token that is set (claude-code-plugins#13586). - assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "true" }), true); - assert.equal(starts({ handoff: "", "credential-present": "false", "fallback-ready": "false" }), false); - assert.equal(starts({ handoff: "", "credential-present": "" , "fallback-ready": "true" }), false); + assert.equal( + starts({ + handoff: "", + "credential-present": "false", + "fallback-ready": "true", + }), + true, + ); + assert.equal( + starts({ + handoff: "", + "credential-present": "false", + "fallback-ready": "false", + }), + false, + ); + assert.equal( + starts({ handoff: "", "credential-present": "", "fallback-ready": "true" }), + false, + ); // A fork, a draft or Dependabot never reaches it either. assert.equal( Boolean(