Skip to content

Guided mode: hand-hold the hunt for a good commit#23

Merged
martinus merged 2 commits into
mainfrom
guided-good-commit-hunt
Jul 6, 2026
Merged

Guided mode: hand-hold the hunt for a good commit#23
martinus merged 2 commits into
mainfrom
guided-good-commit-hunt

Conversation

@martinus

@martinus martinus commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

git bisect can't binary-search until it has both a bad and a good commit. You almost always have the bad one (HEAD), but finding the good anchor means walking backwards through history by hand — with no guidance. This PR adds an advisory guided mode: run the same recipe manually during that hunt and it tells you exactly what to do next.

Workflow

git bisect start
git bisect bad            # HEAD has the bug
python recipe.py          # ← guided
  • HEAD already bad? The recipe doesn't waste time re-testing it — it prints older candidate commits to try instead (each roughly doubling the distance back: ~1w, 2w, 4w, …). --force evaluates anyway.
  • Still bad on an older commit? It says so and offers the next, doubled batch of candidates + git bisect bad.
  • Bug gone? It hands off: git bisect good then git bisect run python recipe.py.
  • Build broke? run() aborts as always and says fix your build script — never mistaken for a good/bad verdict.

Design

Guided output activates only while a bisect is started with a bad commit but no good one yet (refs/bisect/good-* empty and no good in git bisect log). So it is completely silent during a real git bisect run (both endpoints known) and during a pre-start smoke test (no bisect at all) — no fragile "am I under git bisect run?" sniffing. Candidates are resolved by date on the bad commit's ancestry, so they're always valid bisect points; probes past the start of history are dropped. Output is colored/boxed, matching the existing verb-echo style.

Test plan

  • New TestGuided suite (8 tests): already-bad skip guard, --force, each verdict's guidance, the distance-doubling ([7, 14, 28]), and the silence guarantee (good known / no bisect).
  • Full suite green: 76 tests pass (python3 -m unittest discover -s tests).
  • No behavior change to the automated git bisect run path (verified end-to-end: a real run still finds the first bad commit with no guided output).

Docs: new README section "Don't know a good commit yet?" and SPEC §4.9. Version bumped to 0.15.0.

🤖 Generated with Claude Code

martinus and others added 2 commits July 5, 2026 22:39
`git bisect` needs both a bad and a good endpoint before it can binary-search,
but you usually only have the bad one (HEAD). Finding the good anchor meant
manually walking backwards through history with no help. This adds an advisory
"guided mode" that turns each manual `python recipe.py` run of that hunt into a
self-explaining step.

It activates only while a bisect is started with a bad commit but no good one
yet (no `refs/bisect/good-*` and no good in `git bisect log`), so it stays
completely silent during a real `git bisect run` (both endpoints known) and
during a pre-start smoke test (no bisect at all) — no fragile "am I under
bisect run?" sniffing.

Behaviour when active:
- Already-bad guard: refuses to re-evaluate a commit git already knows is bad
  (nothing to learn), pointing at older commits instead. `--force` overrides.
- After a verdict, prints the copy-pasteable next step:
  - good  -> `git bisect good` then `git bisect run python recipe.py`
  - bad   -> `git bisect bad` plus older candidate commits to check out
  - skip  -> older candidates to try
  - abort -> "fix your build script" (an infra problem, never a good/bad verdict)
- Candidate commits double the distance searched (first hunt: ~1w, 2w, 4w),
  resolved by date on the bad commit's ancestry so they're always valid.

Output is colored and boxed, mirroring the existing verb echo style.

Adds a TestGuided suite (8 tests) covering the skip guard, --force, each
verdict's guidance, the doubling, and the silence guarantee. Docs updated in
README (new "Don't know a good commit yet?" section) and SPEC (§4.9). Bumps
version to 0.15.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two refinements to guided mode from review feedback:

1. Step by commit count, not calendar time. Commit count is what governs a
   bisect (it sets the number of steps) and commit density is too uneven for
   time to be a good proxy. Probes now double the number of commits skipped
   (HEAD~s, HEAD~2s, HEAD~4s, s = depth already searched via
   `git rev-list --count HEAD..<newest-bad>`), walking first-parent so each is a
   valid mainline ancestor. Each candidate still shows its committer date for
   orientation.

2. A build failure no longer just says "fix your build script". An old commit
   that won't build is untestable, and why (toolchain drift vs. a broken recipe)
   is a judgement the library can't make — so a failed run() now presents a
   direction choice: an older commit (jump past the break) and a newer one (back
   toward code that builds), plus the reminder to fix the recipe or set
   skip_on_error=True. The user decides; the library still marks nothing and
   moves no HEAD. Recipe errors (uncaught exceptions, unrunnable tests) keep the
   distinct "fix the recipe" message.

Tests updated/added (78 total): commit-count doubling shows [1,2,4] with dates,
build break offers OLDER/NEWER + skip_on_error, recipe error stays distinct from
a build break, and a forced build break on the anchor offers only OLDER. README
and SPEC §4.9 updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@martinus martinus merged commit 2ab9c0c into main Jul 6, 2026
8 checks passed
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