Skip to content

review: diff-base ladder mis-resolves in constrained clones (single-branch / shallow) — deepen-vs-report design fork #625

Description

@kyle-sexton

Plugin: review · Category: baked repo assumption / silent wrong-or-empty diff base
Source: bot review on #591 (chatgpt-codex-connector, two P1 findings) + the maintainer's own thread-1 scope note; confirmed VALID, deferred out of #591's scope as design-shaped.

Summary

#591 fixed the origin/main-baked terminal fallback and the full-depth --single-branch default-base case (fetch resolved default branch, diff against FETCH_HEAD). Two constrained-clone facets of the diff-base ladder remain, both sharing one root — the ladder resolves the base from local refs / a single shared FETCH_HEAD that constrained clones don't populate as assumed — and one fix design fork. They belong together in a single reworked base-resolution path, not re-patched across the five dense one-liners (four reviewer agents + the fanout diff-size snippet), where each inline escalation has demonstrably invited the next bot finding.

Facet A — --depth=1 shallow clone (default actions/checkout shape)

After fetching the resolved default branch at the same shallow depth, git merge-base FETCH_HEAD HEAD finds no common ancestor, so the ladder degrades to echo HEAD and git diff HEAD is empty — the silent no-op #591 set out to eliminate. Reproduced (3-commit main, feature off its tip, --depth=1 --single-branch): after git fetch origin main, merge-base FETCH_HEAD HEAD fails; git fetch --unshallow origin flips is-shallow-repository false and it then resolves.

Facet B — full-depth --single-branch clone with a PR against a NON-default base

The PR_BASE rung (git merge-base "origin/${PR_BASE:-HEAD}" HEAD) — pre-existing, untouched by #591 — relies on a local origin/<base> ref. In a --single-branch clone, git fetch origin "$PR_BASE" populates only FETCH_HEAD, never refs/remotes/origin/<base>, so this rung fails. The ladder then falls to #591's new default-branch rung, which fetches the default branch into FETCH_HEAD (overwriting the PR base) and diffs against the default merge-base rather than the PR's real base (e.g. release) — silently folding the base branch's pre-existing changes into the review as if they were the PR's. git fetch needs --append to add to FETCH_HEAD instead of overwriting; the base must be captured (an explicit rev/ref) before the default-branch fallback runs. #591 changed this scenario's symptom from empty-diff to a wrong, misleading diff base; it was already broken (empty) pre-#591. Maintainer flagged the same root in #591 thread 1: "the pre-existing PR_BASE rung shares the same local-resolution limitation for a non-default PR base in single-branch clones."

Design fork (needs a human decision — hence status: needs-decision)

  1. Fetch-more / deepen — capture each fetched base as an explicit rev before the next fetch overwrites FETCH_HEAD (facet B), and lazily git fetch --unshallow when the shallow merge-base fails (facet A). Correct, but --unshallow on a large repo is a heavy, unbounded download on every affected agent invocation — a cost that should be chosen deliberately, not baked into an unattended pass.
  2. Convention-aligned report-and-stopfanout/SKILL.md already prescribes "report which ref failed and STOP" for an unresolvable base; the agent files currently violate that by silently reaching echo HEAD (facet A) or a wrong base (facet B). Failing loudly is cheap and honest but changes agent behavior on constrained clones.

Picking between "fetch/unshallow at any cost" and "fail loudly", and factoring the shared resolution into one helper, is a real design decision — the maintainer's stated intent is for this logic to live once in a shared default-branch/base helper rather than across five one-liners.

Relationships

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.priority: mediumReal value, no hard deadline; normal backlog flow.status: needs-decisionAwaiting a human or maintainer judgment call.wayfind: designWayfind decision item: design-space or domain-model decision; human in the loop.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions