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
{{ message }}
Repository navigation
A Ticket fails as CI red when its Repair already re-ran the failed checks and they passed #508
In the Spec run for #486 last night, Ticket #489 failed with "CI red on 7a2e53a and the Repair found nothing to fix on the branch", although CI on 7a2e53a was green by then.
From the command log (~/.thirdshift/logs/JacobStephens2/thirdshift/commands/pickup/486-20261007T013901-0400.log, times EDT):
02:41:56: the Repair session itself ran gh run rerun 37581771582 --failed. Attempt 2 passed, completing at 02:44:54.
02:49:24: the Repair session ended, having changed nothing.
02:49:25: thirdshift: "re-running the failed checks on 7a2e53a: test"
02:49:26: "the failed checks on 7a2e53a were not re-run: gh run rerun 37581771582 --failed --repo JacobStephens2/thirdshift failed: run 37581771582 cannot be rerun; its workflow file may be broken"
PR #498 is now green and mergeable, but the Spec run had already stopped. Because issue-486 and PR #496 exist, #486 is no longer a Ready issue, so no Pickup run resumes it.
Expected
When gh run rerun --failed is refused, thirdshift should read the checks on the head commit again before calling the Ticket failed. Here the run had already been re-run, its new attempt passed, and the Ticket should have gone on to merge.
Where
src/ci.rs, rerun_through: if rerun_failed_jobs fails, it returns Ok(None) without looking at the checks' current state. The failed checks it acts on were read before the Repair session ran, so they predate any re-run the session made.
Notes
A Repair session re-running CI is reasonable: its prompt lets it, and here it was the right fix for a flaky test.
Either thirdshift picks up re-runs it didn't start, or the Repair prompt tells the session to leave CI re-runs to thirdshift. The first is more robust.
Category: bug Summary: A refused Check re-run must refresh CI on the unchanged head before a Run is failed as a Declined CI fix.
Current behavior:
The Repair loop retains the failed checks it read before starting a CI-fix Repair. When the Repair leaves the head unchanged, the Check re-run uses that snapshot. If GitHub refuses gh run rerun --failed, rerun_through returns None immediately, and the Repair loop fails the Run as CI red. A Repair can already have re-run those checks and watched them pass, so the retained failures need not describe current CI.
Verification:
The original Command log records Repair re-running workflow run 37581771582 at 02:41:56 EDT, then thirdshift attempting the same re-run at 02:49:25, receiving a refusal at 02:49:26, and failing Ticket Reviewers list the files they read #489 at 02:49:29.
GitHub's attempt 2 confirms success on head 7a2e53afdf7e6933df8bf790b211c40694041466, completed by 02:44:54 EDT. Attempt 1 failed on that same head.
Independently reproduced against checkout f03ac2b7358f2380940bd45c03eb65b5c67d091d using the existing Scenario harness, real git, and fake GitHub/Harness executables: the implement session creates a failing Actions check whose re-run passes; session 2 runs gh run rerun 900 --failed --repo acme/widgets and commits nothing. The fake GitHub then refuses thirdshift's second request because no failed job remains. Assertions confirmed the check was successful, the Run nevertheless exited unsuccessfully with the Declined CI fix cause, two re-run requests were made, and only one Repair ran. cargo test --test triage_508_repro -- --nocapture passed its assertions of the broken behavior. The temporary reproduction test was removed after verification; no fix was implemented during triage.
Desired behavior:
When a Check re-run request fails, determine the outcome from freshly read checks on the same head instead of immediately treating the earlier failure snapshot as current. If those checks have passed, continue normal Delivery and, for a Merge run, Self-merge. If they are pending, watch them finish using the existing interruption behavior. If the branch's own checks are still red, preserve the Declined CI fix outcome without spending another Repair or issuing another re-run for that head. Preserve the existing treatment of Inherited failures and the protection against reading an earlier attempt as the result of a successful re-run request.
The refusal remains visible in progress output, but its error text is not evidence of CI's current state. A failed checks read or an empty listing after previously known failures must not become an unverified successful outcome. When several workflow runs are involved, assess the whole head's CI, including any re-run already started before a later request was refused.
Key interfaces:
rerun / rerun_through and their Result<Option<Ci>> contract: a request refusal alone must not mean there is no current CI outcome to observe.
The CI Outside boundary, checks_on, and watch behavior: reuse deterministic head-commit checks and polling, including current pending checks and Inherited failure classification.
The Repair loop's unchanged-head path: preserve its one-Repair/one-Check-re-run budget and normal delivery/merge gates.
The existing InMemory and Scenario test boundaries can simulate a refused request with checks already green or pending.
ADR-0010 currently says a refused re-run unconditionally fails the Run. Amend that consequence to reflect fresh-check reconciliation; align the domain documentation where necessary.
Acceptance criteria:
An unchanged-head Repair that re-runs failed Actions checks to green is followed by a successful Delivery, even if thirdshift's subsequent re-run request is refused. A regression test exercises this through the Run boundary.
A Merge run in that case reaches Self-merge on the same verified head, rather than failing its Ticket as CI red.
A refused request with current pending checks waits for completion; pending-to-green continues and pending-to-own-red ends as a Declined CI fix. Interruption still stops the watch.
A refused request with current own failures still fails without another Repair or re-run, and reports the refusal.
Fresh checks-read errors and an empty listing after known failures do not produce a successful delivery or merge.
Reconciliation considers all checks on the head when one workflow request succeeded before another was refused; remaining failures and pending checks cannot be ignored.
Existing successful-re-run freshness checks, non-Actions refusal behavior, Inherited failure handling, and merge head verification remain covered and correct.
ADR-0010 and any affected domain wording describe the revised refusal behavior consistently.
Activity
JacobStephens2 commentedon Oct 7, 2026
Agent Brief
Category: bug
Summary: A refused Check re-run must refresh CI on the unchanged head before a Run is failed as a Declined CI fix.
Current behavior:
The Repair loop retains the failed checks it read before starting a CI-fix Repair. When the Repair leaves the head unchanged, the Check re-run uses that snapshot. If GitHub refuses
gh run rerun --failed,rerun_throughreturnsNoneimmediately, and the Repair loop fails the Run as CI red. A Repair can already have re-run those checks and watched them pass, so the retained failures need not describe current CI.Verification:
7a2e53afdf7e6933df8bf790b211c40694041466, completed by 02:44:54 EDT. Attempt 1 failed on that same head.f03ac2b7358f2380940bd45c03eb65b5c67d091dusing the existingScenarioharness, real git, and fake GitHub/Harness executables: the implement session creates a failing Actions check whose re-run passes; session 2 runsgh run rerun 900 --failed --repo acme/widgetsand commits nothing. The fake GitHub then refuses thirdshift's second request because no failed job remains. Assertions confirmed the check was successful, the Run nevertheless exited unsuccessfully with the Declined CI fix cause, two re-run requests were made, and only one Repair ran.cargo test --test triage_508_repro -- --nocapturepassed its assertions of the broken behavior. The temporary reproduction test was removed after verification; no fix was implemented during triage.Desired behavior:
When a Check re-run request fails, determine the outcome from freshly read checks on the same head instead of immediately treating the earlier failure snapshot as current. If those checks have passed, continue normal Delivery and, for a Merge run, Self-merge. If they are pending, watch them finish using the existing interruption behavior. If the branch's own checks are still red, preserve the Declined CI fix outcome without spending another Repair or issuing another re-run for that head. Preserve the existing treatment of Inherited failures and the protection against reading an earlier attempt as the result of a successful re-run request.
The refusal remains visible in progress output, but its error text is not evidence of CI's current state. A failed checks read or an empty listing after previously known failures must not become an unverified successful outcome. When several workflow runs are involved, assess the whole head's CI, including any re-run already started before a later request was refused.
Key interfaces:
rerun/rerun_throughand theirResult<Option<Ci>>contract: a request refusal alone must not mean there is no current CI outcome to observe.Outsideboundary,checks_on, and watch behavior: reuse deterministic head-commit checks and polling, including current pending checks and Inherited failure classification.InMemoryandScenariotest boundaries can simulate a refused request with checks already green or pending.Acceptance criteria:
Out of scope: