You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(pr-patrol): reduce compute waste with issue-type budgets and timeout abandonment
PR Patrol was burning 90%+ of compute on failed attempts:
- Timeouts (30 min each) didn't count toward abandonment, causing infinite retries
- All issue types got the same 40-turn / 30-min budget regardless of complexity
- No early-exit guidance in prompts, so Claude kept trying unfixable issues
- Reflection used expensive Sonnet model for simple log analysis
Changes:
- Unify failure tracking: timeouts now count toward abandonment (2 failures = abandoned)
- Add per-issue-type budgets: missing-issue-ref gets 5 turns/3 min, ci-failure gets 25/15, etc.
- Add "when to stop early" section to prompts with clear unfixable-scenario detection
- CI failure prompt now explicitly lists human-required checks to skip immediately
- Reflection uses haiku model with 5-min timeout instead of sonnet/30-min
- Include pr-patrol tests in vitest config
- Add computeBudget tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Check CI status: gh pr checks ${num} --repo ${repo}
1047
1091
- Read the failing check logs to understand the failure
1048
-
- Fix the issue (build error, test failure, lint error)
1049
-
- Run locally to verify: pnpm build and/or pnpm test
1050
-
- Commit and push the fix`);
1092
+
- **STOP IMMEDIATELY and report** if ANY of these apply:
1093
+
- The check requires a human action (adding a label like \`rules-change-reviewed\`, manual approval, etc.)
1094
+
- The failure is in a Vercel deployment or external service (not a code issue)
1095
+
- The same check is also failing on the \`main\` branch (pre-existing, not caused by this PR)
1096
+
- The failure is a permissions or authentication issue
1097
+
- If the failure IS a code issue you can fix: fix it, run locally to verify (pnpm build / pnpm test), commit and push`);
1051
1098
}
1052
1099
1053
1100
if(issues.includes('missing-testplan')){
@@ -1097,7 +1144,14 @@ ${issues.join(', ')}
1097
1144
- Use git push --force-with-lease (never --force) when pushing rebased branches
1098
1145
- Do not modify files unrelated to the fix
1099
1146
- Do NOT run /agent-session-start or /agent-session-ready-PR — this is a targeted fix, not a full session
1100
-
- Do NOT create new branches — work on the existing PR branch`);
1147
+
- Do NOT create new branches — work on the existing PR branch
1148
+
1149
+
## When to stop early
1150
+
- **If the issue requires human intervention** (adding labels, approvals, external service fixes): output a clear summary of why and stop immediately. Do not attempt workarounds.
1151
+
- **If the issue is pre-existing** (also failing on main, not introduced by this PR): state that and stop.
1152
+
- **If you've tried 2+ approaches and none worked**: stop and summarize what you tried. Do not keep cycling through the same strategies.
1153
+
- **If the fix is "no action needed"** (e.g., no matching issue exists for missing-issue-ref): say so and stop. Not every detected issue requires a code change.
1154
+
- Stopping early with a clear explanation is BETTER than burning through all turns without progress.`);
body: `🤖 **PR Patrol** ran for ${elapsedS}s (${config.maxTurns} max turns, model: ${config.model}).\n\n**Issues detected**: ${pr.issues.join(', ')}\n\n**Result**:\n${summary}`,
1335
+
body: `🤖 **PR Patrol** ran for ${elapsedS}s (${effectiveMaxTurns} max turns, model: ${config.model}).\n\n**Issues detected**: ${pr.issues.join(', ')}\n\n**Result**:\n${summary}`,
1254
1336
},
1255
1337
}).catch(()=>log(' Warning: could not post summary comment'));
1256
1338
}
1257
1339
}elseif(result.hitMaxTurns){
1258
-
constfailCount=recordMaxTurnsFailure(pr.number);
1340
+
constfailCount=recordFailure(pr.number);
1259
1341
outcome='max-turns';
1260
-
reason=`Hit max turns (${config.maxTurns}) — attempt ${failCount}`;
1261
-
log(`${cl.yellow}⚠ PR #${pr.number} hit max turns after ${elapsedS}s${cl.reset}`);
1342
+
reason=`Hit max turns (${effectiveMaxTurns}) — attempt ${failCount}`;
1343
+
log(`${cl.yellow}⚠ PR #${pr.number} hit max turns after ${elapsedS}s (attempt ${failCount})${cl.reset}`);
1262
1344
1263
1345
if(failCount>=2){
1264
-
reason=`Abandoned after ${failCount}max-turns failures`;
1346
+
reason=`Abandoned after ${failCount} failures`;
1265
1347
log(
1266
-
`${cl.red}✗ PR #${pr.number} abandoned after ${failCount}max-turns failures${cl.reset}`,
1348
+
`${cl.red}✗ PR #${pr.number} abandoned after ${failCount}consecutive failures${cl.reset}`,
0 commit comments