Both found while shipping PR #94. Same function, same area, distinct causes. Owner: the ## Stack-Base Resolution Convention section in skills/ba-execute/SKILL.md.
1. The origin/HEAD exclusion never fires
The illustrative loop excludes the symbolic default-branch dup with:
[ "$ref" = "origin/HEAD" ] && continue
But ref comes from --format='%(refname:short)', and refs/remotes/origin/HEAD short-names to origin, not origin/HEAD. Verified:
refs/remotes/origin/HEAD -> origin
So origin/HEAD competes as a distinct candidate and ties with main on every non-stacked branch — same ref, counted twice. Observed live: a confidence = ambiguous warning naming (main, origin) on a branch that is plainly non-stacked.
Impact is a spurious ambiguous, not a wrong base — but ambiguous is a real signal that this makes meaningless, and the convention's own precedence rules lean on it.
Fix: compare against the short name ([ "$short" = "origin" ]), or exclude by full refname.
2. The ranking metric cannot distinguish an ancestor from a sibling
Two branches diverging at the same merge-base tie at the same ahead-count, and nothing breaks the tie — even though only one is a true ancestor. Observed live:
issue-92 and u9-scratch-2 tie at ahead-count 1 (same merge-base). The open-MR host signal doesn't disambiguate — both have open PRs. I picked issue-92 because it's the only true ancestor; u9-scratch-2 is a sibling that diverges at the same commit. The ranking metric as specified can't see that difference.
The session resolved it correctly by reasoning the spec does not contain. A different session could pick the sibling and target a PR at it.
Fix: add git merge-base --is-ancestor "$ref" HEAD as a tie-break before the count comparison. Deterministic, one call per tied candidate, and it encodes the distinction the count metric structurally cannot see.
Why together
Both are candidate-selection defects in the same loop and would be fixed in the same edit. Filing separately would mean two passes over the same twelve lines.
Scope note
Neither was touched in PR #94 — that PR is the ticket write-back, and resolve-stack-base is a different owned operation with its own citation axis.
Both found while shipping PR #94. Same function, same area, distinct causes. Owner: the
## Stack-Base Resolution Conventionsection inskills/ba-execute/SKILL.md.1. The
origin/HEADexclusion never firesThe illustrative loop excludes the symbolic default-branch dup with:
But
refcomes from--format='%(refname:short)', andrefs/remotes/origin/HEADshort-names toorigin, notorigin/HEAD. Verified:So
origin/HEADcompetes as a distinct candidate and ties withmainon every non-stacked branch — same ref, counted twice. Observed live: aconfidence = ambiguouswarning naming(main, origin)on a branch that is plainly non-stacked.Impact is a spurious
ambiguous, not a wrong base — butambiguousis a real signal that this makes meaningless, and the convention's own precedence rules lean on it.Fix: compare against the short name (
[ "$short" = "origin" ]), or exclude by full refname.2. The ranking metric cannot distinguish an ancestor from a sibling
Two branches diverging at the same merge-base tie at the same ahead-count, and nothing breaks the tie — even though only one is a true ancestor. Observed live:
The session resolved it correctly by reasoning the spec does not contain. A different session could pick the sibling and target a PR at it.
Fix: add
git merge-base --is-ancestor "$ref" HEADas a tie-break before the count comparison. Deterministic, one call per tied candidate, and it encodes the distinction the count metric structurally cannot see.Why together
Both are candidate-selection defects in the same loop and would be fixed in the same edit. Filing separately would mean two passes over the same twelve lines.
Scope note
Neither was touched in PR #94 — that PR is the ticket write-back, and
resolve-stack-baseis a different owned operation with its own citation axis.