From 26e51b2bfdc8f15e468bbe99c3110d2489594a3d Mon Sep 17 00:00:00 2001 From: garrytan Date: Sat, 31 Oct 2026 19:41:57 +0000 Subject: [PATCH] chore: changelog and TODOS Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- changelog.d/capy-gst-511-skip-an.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 changelog.d/capy-gst-511-skip-an.md diff --git a/changelog.d/capy-gst-511-skip-an.md b/changelog.d/capy-gst-511-skip-an.md new file mode 100644 index 000000000..8a3e1bc54 --- /dev/null +++ b/changelog.d/capy-gst-511-skip-an.md @@ -0,0 +1,10 @@ +**gstack no longer diffs a PR branch against itself when origin/HEAD names it (GST-511).** A clone made by Capy's PR flow can point `origin/HEAD` at the PR branch. Every default-base chain took `origin/HEAD` first, so with no base given `gstack-diff-scope` printed every `SCOPE_*=false` and `gstack-gate-diff` printed `GATE_SUMMARY: listed=0`: an empty diff that passed. The ship queue, the receipt and pregate read the same wrong base, which sent the review planner to full depth on gstack-evals#96. + +### Fixed +- **The default base** (`lib/default-base.ts`, used by `resolveBaseBranch` and `gstack-gate-diff`, with the same chain in `gstack-diff-scope`) takes a remote's HEAD only when it names a branch other than the checked-out one. Otherwise it tries the PR's base from `gh pr view`, for a same-repository PR only (stopped after 5 seconds, any failure ignored), then `origin/main`, then `origin/master`. A detached HEAD keeps `origin/HEAD`. The branch is compared by its full ref, so a tag with the branch's name can't hide the match. An explicit base works as before. +- **When nothing resolves, the tools fail closed and say why.** `gstack-diff-scope` prints `SCOPE_ERROR=no_base` and a line naming origin/HEAD's target (exit 2). `gstack-gate-diff` prints `GATE_ERROR=no_base ref=origin/HEAD target=origin/ fix=git remote set-head origin ` (exit 2). `resolveBaseBranch` still returns `main`, which origin then lacks, so every reader of `origin/` refuses, and it writes the reason to stderr. +- **`gstack-ship-preflight`** no longer falls back to the local `origin/HEAD` when the remote's HEAD names no branch, so a PR branch that a local `origin/HEAD` names isn't stopped as "on the base branch". When `git ls-remote origin HEAD` itself fails, preflight stops with `STOP: git ls-remote origin HEAD failed: ...; restore access first` instead of skipping the check. + +### Tests +- `test/diff-scope.test.ts`, `test/gate-diff-cli.test.ts`, `test/gstack-ship-policy.test.ts`: a clone whose `origin/HEAD` names the checked-out branch scopes and lists the PR against `origin/main`. They also cover the PR base from a gh stub, a tag named like the branch, the default branch's own uncommitted work, a detached HEAD, and the fail-closed line when no other base exists. +- `test/ship-preflight.test.ts`: a remote whose HEAD names no branch, beside a local `origin/HEAD` that names the feature branch, no longer stops the ship, and a failed `ls-remote` stops it before merging.