@@ -215,13 +215,110 @@ jobs:
215215 # naming the cause, not a silently empty shard. An EMPTY shard file must
216216 # short-circuit the test step below: `turbo run test` with zero --filter
217217 # args runs the entire workspace.
218+ #
219+ # WHERE THE AFFECTED DIFF STARTS (#6195, the #6129 family's third
220+ # consumer). The one thing this base must never be is
221+ # `github.event.pull_request.base.sha`.
222+ #
223+ # The payload's `base.sha` is frozen when the PR is OPENED and does not
224+ # move on `synchronize`. HEAD, meanwhile, is the merge ref
225+ # (`refs/pull/N/merge`) that the checkout above resolves by default on a
226+ # `pull_request` event — no `ref:` is given, so this job stands on a merge
227+ # commit containing everything main has today. Everything main gained
228+ # while the PR sat open therefore lands between the two, and
229+ # `turbo ls --affected` reads it as this PR's own changes: packages only
230+ # SOMEBODY ELSE's merged PR touched get tested on this shard.
231+ #
232+ # The direction is conservative — the frozen base is an ancestor of HEAD,
233+ # so its file set is a strict SUPERSET of this PR's own. Nothing that
234+ # should run is skipped; what degrades is the optimisation itself, and it
235+ # degrades with how long the PR has been open. At ~18 merges a day an
236+ # affected-only shard drifts back toward a full run.
237+ #
238+ # Measured on turbo 2.10.7 against a real merge-ref fixture (base branch
239+ # moved 1 commit touching pkg-b; this PR touched pkg-a only):
240+ # TURBO_SCM_BASE=<frozen base.sha> -> pkg-a, pkg-b
241+ # TURBO_SCM_BASE=merge-base(origin/main,HEAD) -> pkg-a
242+ #
243+ # Four spellings that look like the fix and are not:
244+ # - `base.sha...HEAD` (three dots). Three-dot means
245+ # `merge-base(base.sha, HEAD)..HEAD`, and the frozen sha is ALREADY an
246+ # ancestor of HEAD, so it IS its own merge base and the set does not
247+ # move. Measured: still both packages. (pr-automation.yml records the
248+ # same result for its own diff — same fact, one family.)
249+ # - `HEAD^1`. Correct on a merge ref and silently wrong the day someone
250+ # gives this checkout a `ref:`, where parent^1 becomes the PR's
251+ # previous commit. `merge-base` is right under BOTH checkouts.
252+ # - Dropping the variable and letting turbo default to `main`. Measured
253+ # in a CI-shaped clone: `fetch-depth: 0` populates
254+ # `refs/remotes/origin/*`, NOT local heads, so there is no local `main`
255+ # — and turbo does not error, it silently returns the ENTIRE
256+ # workspace, untouched packages included. Safe, and the whole
257+ # optimisation gone.
258+ # - `TURBO_SCM_BASE=origin/$BASE_REF`, letting turbo resolve the ref.
259+ # Measured correct today, but it rests the shard's package set on
260+ # `turbo ls`'s internal choice of dot-ness — undocumented, and
261+ # `turbo ls` is experimental (see above). Resolving to a commit here
262+ # leaves turbo no choice to make.
218263 - name : Compute this shard's package set
219264 env :
220- TURBO_SCM_BASE : ${{ github.event.pull_request.base.sha }}
265+ BASE_REF : ${{ github.event.pull_request.base.ref }}
266+ PINNED_BASE_SHA : ${{ github.event.pull_request.base.sha }}
221267 run : |
268+ SCM_BASE=''
222269 if [ "${{ github.event_name }}" = "pull_request" ]; then
223- pnpm exec turbo ls --affected --output=json > "$RUNNER_TEMP/turbo-ls.json"
270+ if [ -z "$BASE_REF" ]; then
271+ echo "::warning::This pull_request event carries no base branch, so the affected-set diff base cannot be computed."
272+ else
273+ # `fetch-depth: 0` above already makes this resolve — the fetch is
274+ # the guard for the day that changes, not the normal path.
275+ #
276+ # `git cat-file -e` rather than the more idiomatic strict
277+ # `git rev-parse` spelling, and the reason is not style.
278+ # check-shard-attestation.mjs classifies a job as an aggregate GATE
279+ # when the job's joined `run:` text contains BOTH the string
280+ # "check-shard-attestation.mjs" and, as a bare substring, that
281+ # script's own dash-dash-verify flag. This job already carries the
282+ # first (its --emit step at the bottom), so spelling that flag
283+ # anywhere in this step — including in a comment, since comments
284+ # are part of `run:` — silently reclassifies the shard job as a
285+ # gate. The drift guard then fails with two complaints that name
286+ # nothing to do with the real edit ("its job-level if: is not
287+ # always()", "never downloads the shard attestations it claims to
288+ # count"). Measured both ways on this very change; do not "tidy"
289+ # this back.
290+ if ! git cat-file -e "refs/remotes/origin/$BASE_REF^{commit}" 2>/dev/null; then
291+ git fetch --no-tags --quiet origin "+refs/heads/$BASE_REF:refs/remotes/origin/$BASE_REF" \
292+ || echo "::warning::Could not fetch origin/$BASE_REF; the merge-base resolution below will decide."
293+ fi
294+ # `if !` rather than a bare assignment on purpose: these steps run
295+ # under `bash -e`, where a failing command substitution kills the
296+ # step with no message at all.
297+ if ! SCM_BASE=$(git merge-base "refs/remotes/origin/$BASE_REF" HEAD); then
298+ SCM_BASE=''
299+ fi
300+ fi
301+ fi
302+ if [ -n "$SCM_BASE" ]; then
303+ # The drift is printed, not just corrected: nothing in this log ever
304+ # said which commit the affected diff started from, which is why the
305+ # decay was invisible.
306+ DRIFT=$(git rev-list --count "$PINNED_BASE_SHA..$SCM_BASE" 2>/dev/null || echo '?')
307+ echo "Affected-set diff base: $SCM_BASE (merge-base of origin/$BASE_REF and HEAD)"
308+ echo "Frozen payload base.sha: $PINNED_BASE_SHA -- $BASE_REF has moved $DRIFT commit(s) since it was frozen, and that drift is exactly what this step used to charge to this PR."
309+ TURBO_SCM_BASE="$SCM_BASE" pnpm exec turbo ls --affected --output=json > "$RUNNER_TEMP/turbo-ls.json"
224310 else
311+ # Falling back to the FULL package list, never to the frozen
312+ # base.sha. This is not the #4690 silent-skip anti-pattern: that is
313+ # about a gate PASSING on input it could not read, and the full list
314+ # is a strict superset of the affected one — this shard still runs
315+ # everything it would have run and more. Cost is minutes; the
316+ # alternative is a red Test Core on a PR with nothing wrong with it.
317+ # Push and merge-queue builds take this branch by design (the queue
318+ # result IS the next main, so it gets main's validation).
319+ if [ "${{ github.event_name }}" = "pull_request" ]; then
320+ echo "::warning::Could not resolve merge-base(origin/$BASE_REF, HEAD); falling back to the full package list for this shard rather than diffing from the frozen base.sha (#6195)."
321+ fi
225322 pnpm exec turbo ls --output=json > "$RUNNER_TEMP/turbo-ls.json"
226323 fi
227324 node scripts/partition-test-shards.mjs "$RUNNER_TEMP/turbo-ls.json" \
0 commit comments