diff --git a/.github/workflows/qwen-autofix.yml b/.github/workflows/qwen-autofix.yml index fca1b5cbc95..f9bb4a86cd9 100644 --- a/.github/workflows/qwen-autofix.yml +++ b/.github/workflows/qwen-autofix.yml @@ -106,8 +106,13 @@ env: # hostile commenter cannot steer the agent. TRUSTED_ASSOC: '["OWNER", "MEMBER", "COLLABORATOR"]' # Hard cap on automated review-address rounds per PR. After this the bot stops - # and leaves the PR for a human. - MAX_ROUNDS: '5' + # and leaves the PR for a human. Raised from 5: across the last 40 bot PRs + # only 3 ever reached the cap and all 3 merged AT it (one having spent two of + # its five rounds on the verify-gate ENOENT that #7330 fixed), so the ceiling + # was near enough to bind on a bad day without any headroom for one. The cap + # exists to stop an unproductive LOOP, not to ration ordinary iteration — + # a genuinely stuck PR still stops, just later. + MAX_ROUNDS: '10' # An auth/access model error (401/402/403, "no access"/"does not exist") # never self-heals - only a maintainer can fix the key - and every retry # costs an agent run AND a PR comment. Cap those attempts far below diff --git a/scripts/tests/qwen-autofix-workflow.test.js b/scripts/tests/qwen-autofix-workflow.test.js index c8b6094916e..bc6b2004673 100644 --- a/scripts/tests/qwen-autofix-workflow.test.js +++ b/scripts/tests/qwen-autofix-workflow.test.js @@ -218,7 +218,21 @@ describe('qwen-autofix workflow', () => { expect(workflow).toContain( 'AUTOFIX_BOT: "${{ vars.AUTOFIX_BOT_LOGIN || \'qwen-code-dev-bot\' }}"', ); - expect(workflow).toContain("MAX_ROUNDS: '5'"); + // The round budgets are tuning knobs; what must hold is their ORDERING. + // Asserting the literal numbers only detected edits — it would not catch + // a cap that stopped binding, which is the failure that matters. + const num = (key) => + Number(workflow.match(new RegExp(`\\b${key}: '(\\d+)'`))?.[1]); + const strictRounds = num('MAX_ROUNDS'); + const takeoverRounds = num('TAKEOVER_MAX_ROUNDS'); + const authRounds = num('API_AUTH_MAX_ROUNDS'); + // A strict cap at or above the takeover cap makes the takeover label a + // no-op; an auth sub-cap at or above the strict cap stops short-circuiting + // the retries only a maintainer can fix, which is what it exists for. + expect(strictRounds).toBeGreaterThan(0); + expect(strictRounds).toBeLessThan(takeoverRounds); + expect(authRounds).toBeGreaterThan(0); + expect(authRounds).toBeLessThan(strictRounds); expect(workflow).toContain("MAX_OPEN_AUTOFIX_PRS: '5'"); expect(reviewScanJob).toContain('isCrossRepository'); expect(reviewScanJob).toContain('not an open main-targeting PR');