Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/roadmaps/roadmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17099,3 +17099,19 @@ roadmap:
labels:
- kind:triage
notes: null
- id: PMAT-3186
github_issue: 3186
item_type: task
title: 'guard: resolve_base refuses every stacked merge-group entry (#3186, packing P0)'
status: planned
priority: medium
assigned_to: null
created: 2026-09-12T16:34:18Z
updated: 2026-09-12T16:34:18Z
spec: null
acceptance_criteria: []
phases: []
subtasks: []
estimated_effort: null
labels: []
notes: null
28 changes: 28 additions & 0 deletions scripts/check_roadmap_diff_additive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,34 @@ EOF
*"never the tree against itself"*) printf 'ok row %-2s push shape, parent not fetched (depth-1): refused by name, never HEAD itself\n' "$row" ;;
*) printf 'FAIL row %-2s push shape, parent not fetched: refused for the wrong reason (rc=%s): %s\n' "$row" "$rc5" "$err5"; fails=1 ;;
esac
# Rows 19-20: a STACKED merge-group entry at depth 1 — the head's single parent
# is the previous entry's squash, not the origin/main tip. Under merge_group it
# deepens and names that parent; with deepening disabled (the mutation) it is
# refused by name — the shape that turned two of every three queue builds RED
# on 2026-09-12 (runs 34704287677, 34704288441). Self-contained repo: main =
# c1 (the tip the queue started from) -> c2 (entry 1's squash) -> c3 (entry 2's
# squash); origin/main := c1; a depth-1 clone sees c3 with c2 not fetched.
row=$((row + 1))
Q="$TD/stacked-src"; rm -rf "${Q:?}"; ( git init -q -b main "$Q" && cd "$Q" && git config user.email t@t && git config user.name t \
&& cp "$TD/base.yaml" r.yaml && git add r.yaml && git commit -qm c1 \
&& cp "$TD/append.yaml" r.yaml && git commit -qam c2-entry-1-squash \
&& printf 'entry-2\n' > other.txt && git add other.txt && git commit -qm c3-entry-2-squash && git branch -q queue-base 'HEAD~2' ) 2>/dev/null
# The job fetches origin/main at depth 1 (its object IS present); c2 is not. A shallow clone cannot
# point a ref at an object it lacks, so the tip is fetched by name instead of update-ref'd.
rm -rf "${Q:?}.clone"; git clone -q --depth=1 -b main "file://$Q" "$Q.clone" 2>/dev/null; git -C "$Q.clone" fetch -q --depth=1 origin '+queue-base:refs/remotes/origin/main' 2>/dev/null
want6=$( git -C "$Q" rev-parse 'HEAD^1' )
got6=$( cd "$Q.clone" && GITHUB_EVENT_NAME=merge_group bash -c '. "$0" --lib-only; REPO_ROOT="$1"; resolve_base HEAD && printf "%s|%s" "$BASE_REF" "$BASE_HOW"' "$SELF" "$Q.clone" 2>/dev/null ) || true
case "$got6" in "$want6|single parent (stacked merge_group entry"*) printf 'ok row %-2s stacked merge_group entry at depth-1 -> deepened, base = the previous entry squash\n' "$row" ;;
*) printf 'FAIL row %-2s stacked merge_group entry: wanted %s|single parent (stacked merge_group entry..., got %s\n' "$row" "$want6" "$got6"; fails=1 ;; esac
row=$((row + 1))
rm -rf "${Q:?}.clone"; git clone -q --depth=1 -b main "file://$Q" "$Q.clone" 2>/dev/null; git -C "$Q.clone" fetch -q --depth=1 origin '+queue-base:refs/remotes/origin/main' 2>/dev/null
rc7=0; err7=$( cd "$Q.clone" && GITHUB_EVENT_NAME=merge_group ROADMAP_DIFF_NO_DEEPEN=1 bash -c '. "$0" --lib-only; REPO_ROOT="$1"; resolve_base HEAD' "$SELF" "$Q.clone" 2>&1 >/dev/null ) || rc7=$?
case "$rc7:$err7" in
0:*) printf 'FAIL row %-2s stacked entry with deepening disabled: resolved a base (rc=0) — the mutation did not bite\n' "$row"; fails=1 ;;
*"is not a merge commit nor a commit on the origin/main tip"*) printf 'ok row %-2s stacked entry with deepening disabled (mutation): refused by name\n' "$row" ;;
*) printf 'FAIL row %-2s stacked entry with deepening disabled: refused for the wrong reason (rc=%s): %s\n' "$row" "$rc7" "$err7"; fails=1 ;;
esac
rm -rf "${Q:?}" "${Q:?}.clone"

if [ "$fails" -ne 0 ]; then
printf '\nSELF-TEST FAILED (%s/%s rows)\n' "$((row - fails + fails))" "$row"
Expand Down
18 changes: 18 additions & 0 deletions scripts/lib/resolve_base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ resolve_base() {
if [ -n "$p1" ] && [ "$p1" = "$main_tip" ]; then
BASE_REF="$p1"; BASE_HOW="single parent == origin/main tip (merge_group squash head, shallow checkout)"; return 0
fi
# A STACKED merge-group entry (queue position >= 2). GitHub builds entry N as a
# squash on top of entry N-1's squash, so the head has ONE parent that is NOT the
# origin/main tip and, at fetch-depth 1, is not fetched either. Every rule above
# refuses it, so with max_entries_to_build=3 two of every three queue builds were
# RED on this resolver alone (2026-09-12: groups 34704287677 and 34704288441, each
# after passing 82,085 workspace tests on gx10). The base that names THIS entry's
# own diff is exactly that parent: deepen the shallow history by one commit and
# use it. Only a merge_group run may deepen — a push-shape depth-1 head stays
# refused (never the tree against itself) — and ROADMAP_DIFF_NO_DEEPEN=1 is the
# case table's mutation.
if [ -n "$p1" ] && [ "${GITHUB_EVENT_NAME:-}" = merge_group ] && [ "${ROADMAP_DIFF_NO_DEEPEN:-0}" != 1 ]; then
if ! git -C "$REPO_ROOT" cat-file -e "$p1^{commit}" 2>/dev/null; then
git -C "$REPO_ROOT" fetch -q --deepen=1 origin 2>/dev/null || git -C "$REPO_ROOT" fetch -q origin "$p1" 2>/dev/null || true
fi
if git -C "$REPO_ROOT" cat-file -e "$p1^{commit}" 2>/dev/null; then
BASE_REF="$p1"; BASE_HOW="single parent (stacked merge_group entry: the previous entry's squash, fetched by deepening the shallow checkout)"; return 0
fi
fi
printf '%s: merge-base(origin/main, %s) is unresolvable (shallow checkout) and %s is not a merge commit nor a commit on the origin/main tip,\n' "$PROG" "$head" "$head" >&2
printf ' so no base can be named. A pull_request job checks out refs/pull/N/merge, a merge_group job the queue head; run with an explicit <base> otherwise.\n' >&2
return 1
Expand Down
Loading