Skip to content

Inherited failures fail the Run without a Repair - #225

Merged
JacobStephens2 merged 2 commits into
issue-221from
issue-103
Oct 1, 2026
Merged

JacobStephens2 merged 2 commits into
issue-221from
issue-103

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

A failed check that also failed on the Base branch commit the head last merged in is an Inherited failure (ADR 0008). The Run now recognises it itself, before any Repair.

 RepairLoop::run, each round
   merge origin/<base>, push
+  base commit = merge-base(HEAD, origin/<base>)
-  watch CI on head
+  watch CI on head; on red, read the base commit's checks once and
+  split the failed checks by name: own | inherited
   green or absent -> done, or go round if the Base branch moved
-  red -> CI-fix Repair with every failed check
+  red, some own -> CI-fix Repair with the own failures;
+                   the prompt lists the inherited ones as
+                   "Also failing on `<base>`; don't fix"
+  red, all inherited ->
+    Base branch moved since? merge it again (a Base move), watch CI again
+    otherwise fail: "CI red on <check>[, <check>…], which also fails
+                     on <base> at <short sha>; fix <base> first"
  • A check is Inherited only if it is Failed on both commits. Pending, passed or missing on the Base branch commit means it is the branch's own, as today. Nothing triggers or waits for the Base branch's CI, and no log text is read.
  • The loop is shared, so plain Runs, Merge runs (no Self-merge), a Ticket's Run against the Spec branch, and the Spec PR all get it. The Failed run path is unchanged: the pull request goes back to a draft.
  • New generated prompt page: prompts/ci-fix-repair-inherited.md. README updated.

Seam under test: the existing black-box seam, the real binary with the fake gh and claude (tests/support::Scenario), setting checks on both commits with gh fake checks / gh fake statuses. The prompt page keeps its golden-file test.

Evidence

  • Before: checks_that_also_fail_on_the_base_branch_commit_fail_the_run_without_a_repair failed: the Run printed CI red; starting Repair 1 of 5 and started a repair-1 session.
    After: it passes: one session (implement), stderr has Inherited failures (also failing on main at <sha>): test, lint, deploy/preview and the cause, the PR is a draft, and the failure commit is thirdshift: failed run (CI red on test, lint, deploy/preview, which also fails on main at <sha>; fix main first).

New tests, by acceptance criterion:

tests/ci.rs
  checks_that_also_fail_on_the_base_branch_commit_fail_the_run_without_a_repair
  with_mixed_failures_the_repair_fixes_only_the_branchs_own_and_the_run_then_fails_on_the_inherited
  a_check_still_pending_on_the_base_branch_commit_is_handed_to_a_ci_fix_repair
  a_check_passed_or_missing_on_the_base_branch_commit_is_handed_to_a_ci_fix_repair
  when_the_base_branch_moved_since_inherited_failures_it_is_merged_again_and_ci_watched_again
  a_base_branch_that_moved_and_is_still_red_fails_the_run_naming_its_new_commit
tests/merge_run.rs
  a_merge_run_whose_red_checks_also_fail_on_the_base_branch_commit_does_not_merge
tests/spec_run.rs
  a_ticket_whose_red_check_also_fails_on_the_spec_branch_shows_the_cause_in_the_checklist
  a_spec_pr_whose_red_check_also_fails_on_the_base_branch_commit_gets_no_repair

cargo test: 467 passed, 0 failed. The existing CI tests pass with no change to their bodies. cargo fmt --check and cargo clippy --all-targets are clean.

Merge Danger

Door: two-way

Reverting restores a CI-fix Repair for every red check.

Blast Radius: Runs with red CI

  • Any red CI now costs one more read of the Base branch commit's checks. If that read fails, the Run fails, like any other gh error in the loop.
  • Known trade-off from ADR 0008: a branch that breaks a check in a different way while the Base branch's copy is already red gets no Repair. Nothing merges past it.
  • A Base branch that keeps moving while still red ends as origin/<base> kept moving, not the Inherited failure cause, because each round counts as a Base move.

Unaddressed findings

Standards

  • FailedChecks { own, inherited } has public fields, so the loop knows that an empty own means "all Inherited" (suggested: a third Ci variant or a method). Skipped: the loop needs both lists in the mixed case, and a third variant would carry the same list in two shapes.
  • ci::watch now both watches and compares. Skipped: the Spec (Inherited failures: fail fast on a red Base branch, or fix it with a Base fix #221) asks for exactly this ("the result of watching CI grows to separate the branch's own failures from Inherited failures").
  • Possible Duplicated Code: base_branch_moved + count_base_move in both the green and red arms. Skipped: two lines with different follow-ups (return or go round); a helper would hide more than it saves.
  • Possible Duplicated Code: "also failing on <base> at <sha>" in the progress line and the cause. Skipped: two different sentences that share a clause; the cause's wording is fixed by the issue.
  • Possible Duplicated Code: checks_on_base / inherited_failure helpers written per test file. Skipped: the repo's test files each keep their own copies of such helpers (checks_on_head, RED, base_moves_on).
  • Possible Shotgun Surgery: the cause wording appears in code, README, CONTEXT.md and tests. Skipped: same as every other Failed run cause here.

Spec

  • Mixed failures are tested for a plain Run only, not for Merge runs or the Spec PR. Skipped: the loop is shared, and each of those has an all-Inherited test.
  • Criss-cross history: git merge-base HEAD origin/<base> picks one best common ancestor. Skipped: the Issue branch only ever merges the Base branch in, so the newest merged Base commit is the merge base; it also holds when another Run's fetch moves the shared remote-tracking ref.
  • A Base branch that keeps moving while still red ends with kept moving, not the Inherited failure cause. Skipped: the issue says such a round is "counted as a Base move", and the budget's own cause is what a spent budget reports.
  • An error reading the Base branch commit's checks fails the Run instead of going on to a Repair. Skipped: consistent with every other GitHub read in the loop; hiding it would start Repairs the comparison should have prevented.
  • Scope beyond Inherited failures fail the Run without a Repair #103: the extra prompt page, the Inherited failures (…) progress line, README edits. Kept: prompts/ must show every prompt the binary sends, the progress line is story 33 of Inherited failures: fail fast on a red Base branch, or fix it with a Base fix #221, and the README documents the Run's behavior.

Closes #103

🤖 Generated with Claude Code

JacobStephens2 and others added 2 commits October 1, 2026 01:28
A failed check that also failed, under the same name, on the Base branch
commit the head last merged in is an Inherited failure (ADR 0008). The CI
watcher now splits the failed checks into the branch's own and Inherited
ones. A CI-fix Repair is given only the branch's own, with the Inherited
ones listed as not to fix. When only Inherited failures are left, the Run
merges the Base branch again if it moved, and otherwise fails naming the
checks, the Base branch and its commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tively, test a still-red moved Base branch

A check is an Inherited failure only if every check of its name on the Base
branch commit failed. Commit statuses and a Base branch that moved but is
still red are now covered through the binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant