Repository navigation
Description
This was generated by AI during triage.
What happened
thirdshift merge https://github.com/JacobStephens2/cascade/issues/18 (thirdshift 0.3.0) spent all 5 Repairs on a CI failure that no Repair could fix. The Android build check failed during setup (android-actions/setup-android@v3 → Failed to find package 'tools'), and it fails the same way on the Base branch.
Repair 1 diagnosed this correctly, made no commit, and added a note to the PR body. After that, each round:
thirdshift: merging origin/main into issue-18
thirdshift: pushing issue-18
thirdshift: waiting up to 60s for CI on 209580e
thirdshift: CI failed on 209580e: build
thirdshift: CI red; starting Repair N of 5
The head was 209580e the whole time, so every round read the same failed checks. Repairs 2–5 re-ran Repair 1's investigation and came to the same conclusion (about $0.40 and several minutes wasted). The Run ended with repairs exhausted: CI red, which hides the real reason: the Repair decided there was nothing on the branch to fix.
Logs: ~/.thirdshift/logs/JacobStephens2-cascade-issue-18-20260927T155413Z-repair-{1..5}.jsonl, PR JacobStephens2/cascade#19.
Agent Brief
Category: bug
Summary: End the Repair loop when a CI-fix Repair leaves the head unchanged, instead of re-checking the same commit.
Current behavior:
In the Repair loop, a failed CI result starts a CI-fix Repair and then goes back round. If the Repair made no commit (and the Base branch hasn't moved, so merging it is a no-op), the next round watches CI on the same head, gets the same failure, and starts another CI-fix Repair. This repeats until the MAX_REPAIRS budget runs out, and the Run fails with repairs exhausted: CI red.
Desired behavior:
After a CI-fix Repair, if the head is the same commit whose CI just failed, the Run stops going round and becomes a Failed run with a cause that says so. Suggested wording: CI red on <short sha> and the Repair found nothing to fix on the branch. Failed-run handling applies as usual: push, convert the PR to a draft, print the session log path. The log path should be the one for the Repair that declined.
A CI-fix Repair that commits still goes round as it does today. So does a round where the head changed for some other reason, such as the Base branch moving and a new merge commit.
This follows the rule the loop already uses for a failed Self-merge: when a round finds nothing to fix, the Run fails instead of retrying (see the PolicyRefusal term in CONTEXT.md).
Key interfaces:
- The Repair loop's
Ci::Failedbranch: compare the head before and after the CI-fix Repair session. - The Failed-run cause string, as printed in
thirdshift: failed run (...)and in the Failed-run marker commit. - CONTEXT.md: if this adds a new ending (for example a "declined CI fix"), give it a glossary term, the same way PolicyRefusal has one.
Acceptance criteria:
- A test where CI fails and the CI-fix Repair makes no commit shows exactly one Repair started and the Run failing with the new cause. It must not say
repairs exhausted. - A test where the CI-fix Repair commits and CI then passes still succeeds (existing behavior).
- A test where the first CI-fix Repair commits, CI fails again, and the second Repair makes no commit fails after the second Repair.
- The existing
repairs exhausted: CI redtest still passes when every Repair commits and CI stays red. - CONTEXT.md and the README/help describe the new ending wherever they list how a Run fails.
Out of scope:
- Deciding whether a check that is also red on the Base branch should block the Run. That's a separate policy question, tracked in its own issue.
- Re-running CI on an unchanged head (
gh run rerun) to get past flaky checks. - Changing
MAX_REPAIRS.
Activity
JacobStephens2 commentedon Sep 27, 2026
Related: #103 covers the policy question of checks that are also red on the Base branch.