iceboundrock / iceboundrock/AutoForge

Pin the reviewed merge base next to the base branch name in the review binding

Open
#96 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
0
Forks
0
Avg merge
8h 56m
Merged PRs (30d)
40

Description

Problem

After #68 / #93 a review is bound to the PR it was posted on, the reviewed HEAD and the base branch by name (reviewed_base_ref, in state and in the ai-review-result marker). The name identifies the branch the change is proposed into, but not the base revision the reviewed diff was computed against.

The diff a reviewer reads (gh pr diff) is HEAD against the merge base of HEAD and the base branch. Two events change that diff without changing the base name or the HEAD:

  • the base branch is rewritten under the same name (force-push, reset) so that the merge base moves;
  • rarer, a retarget between two branches that happen to share the merge base is not a diff change, but the name check already treats it as one (stale → REVIEW), which is the safe direction.

Ordinary commits landing on the base branch do not move the merge base and do not change the reviewed diff; the "PR must be up to date with its base before merging" policy is the repository's branch-protection setting, which the merge gate already honours through GitHub's mergeStateStatus (BEHIND is refused). That is why the base is bound by name rather than by the base branch tip: binding the tip would send every open PR back to REVIEW each time anything merges, for a re-review of an identical diff.

Raised in the review of #93 (recommended direction: "the exact base revision or equivalent merge-base snapshot if the reviewed diff must be pinned").

Why not in #93

#93 closes the reachable gaps of #68 (PR substitution at the same HEAD; recovery adopting a comment posted against another base). Pinning the merge base needs a new GitHub read (repos/{owner}/{repo}/compare/{base}...{head}merge_base_commit.sha; gh pr view does not expose it and GraphQL baseRefOid is a stale snapshot, not the live tip nor the merge base), a fake for it, two new state fields with load validation, a marker field, and gate changes before and after the write. It is a strengthening of an invariant #93 already establishes, not a correctness requirement of it.

Recommended direction

  • Read the merge base of (reviewed HEAD, base branch) through GitHubClient right before the reviewer is launched (_bind_review_head), persist it next to current_base_ref (current_merge_base_sha), re-read it after the round (_apply_review: moved → stale), and record it with the binding (reviewed_merge_base_sha).
  • Carry it in the ai-review-result marker (reviewed_merge_base_sha) and include it in ReviewClaim.key, so recovery adopts only a comment for the same diff. A marker without it is handled like one without reviewed_base_ref today: not this round's, not a defect.
  • Merge gate (_verify_pr_for_merge, both before the write and on the post-write read): a merge base that differs from the reviewed one is revision drift → REVIEW (_revision_drift_to_review), like a HEAD or base move.
  • Do not bind the base branch tip.
  • State protocol bump per docs/agent-guides/state-and-recovery.md; status output; docs (workflow.md "Bind reviews to PR HEAD SHA and to the PR identity", github-safety.md "Before REVIEW" / "Before MERGE").

Files

src/autoforge/github.py, src/autoforge/claims.py, src/autoforge/engine.py (_bind_review_head, _apply_review, _review_comments, _verify_pr_for_merge, _merge_step), src/autoforge/state.py, src/autoforge/prompts/review.md, tests/conftest.py (FakeGitHub merge-base support), tests/test_engine.py, tests/test_claims.py, tests/test_state.py.

Acceptance criteria

  • A base branch rewritten under the same name after a clean review (merge base moved, HEAD and base name unchanged) sends READY_FOR_MERGE / MERGE back to REVIEW and merges nothing; the same on the post-write read when the PR is still OPEN.
  • Ordinary commits on the base branch (merge base unchanged) do not invalidate the review; the gate's existing BEHIND handling is unchanged.
  • REVIEW re-entry does not adopt a round comment whose marker names another merge base; a result naming one is rejected.
  • A pre-existing marker without the field is ignored, not a defect.
  • Persisted fields are validated on load; the protocol bump follows the documented rule for files parked in the merge phases.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the existing binding and merge-gate paths in src/autoforge/engine.py, then read the GitHub client, claims, state, and recovery documentation named in the issue. Run the relevant tests in tests/test_engine.py, tests/test_claims.py, tests/test_state.py, and update tests/conftest.py for merge-base support. Done means merge-base drift returns the workflow to REVIEW, unchanged merge bases remain valid, markers and persisted state validate correctly, and the documented protocol and status output are updated.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, python
Domain
api, backend, documentation, testing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.