Skip to content

fix(ci): pin the breadcrumb job's checkout to the validated commit - #137

Merged
thecodedrift merged 1 commit into
mainfrom
fix/breadcrumb-workflow-run-ref
Aug 21, 2026
Merged

fix(ci): pin the breadcrumb job's checkout to the validated commit#137
thecodedrift merged 1 commit into
mainfrom
fix/breadcrumb-workflow-run-ref

Conversation

@thecodedrift

Copy link
Copy Markdown
Member

#132 and #133 crossed. #132 moved the nightly to workflow_run, where every checkout must carry ref: ${{ github.event.workflow_run.head_sha }}; the breadcrumb job #133 added was written against the push trigger and merged without it.

On main right now, gate and publish pin the ref and assert HEAD; breadcrumb does neither.

Why this is not cosmetic

Under workflow_run, github.sha is the default branch tip at event time. So the job checks out whatever main has moved to and succeeds — running a copy of nightly-breadcrumb.cjs that Validate never saw, while announcing a nightly built from a different commit. An empty ref: fails the same way: actions/checkout falls back to the default branch and exits 0. That is exactly the fail-open the two other jobs assert against, and it reads as a normal green run.

The job now pins the ref and asserts HEAD against it, matching gate and publish line for line (including the "payload carried no head_sha" branch).

What deliberately does not change

  • No restated gate-0 conditions. breadcrumb needs publish, which needs gate and is if:-gated on its output — a skipped gate skips publish, which skips this. Verified against the parsed workflow rather than assumed.
  • No re-derived short sha. The job consumes needs.publish.outputs.version, the once-stamped version, and parses the build time and commit back out of it. Nothing here abbreviates a sha, so the prefix-comparison change in f5b3797 has nothing to interact with.
  • No change to the credential split. pull-requests: write, contents: read, no id-token.

Verification

pnpm lint exit 0 · node --test .github/scripts/*.test.cjs 178 pass, 0 fail · pnpm openspec validate --all --strict 24 passed, 0 failed. Parsed the workflow and confirmed all three jobs now carry the same ref:, and that the needs/if chain reaches gate 0 transitively.

The first real proof is the first qualifying push after this merges — GitHub loads a workflow_run workflow from the default branch, so this cannot be exercised on its own PR.

Refs #128
Refs #127

Copilot AI lite review requested due to automatic review settings August 21, 2026 17:11
@thecodedrift thecodedrift added the skip-changeset PR intentionally ships no release note (bypasses the changeset requirement) label Aug 21, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the breadcrumb job in the nightly release workflow so it checks out (and verifies) the exact commit that Validate ran on when triggered via workflow_run, preventing “fail-open” checkouts of the default branch tip.

Changes:

  • Pin actions/checkout in breadcrumb to github.event.workflow_run.head_sha.
  • Add a guard step that fails the job if head_sha is missing or if the checked-out HEAD does not match the validated commit.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

thecodedrift added a commit that referenced this pull request Aug 21, 2026
The nightly has failed on every push since #132 merged — twice, on f5b3797
and 20f18f6 — with:

    Failed to find where HEAD diverged from "main".
    Does "main" exist and it's synced with remote?

`changeset status` resolves baseBranch from .changeset/config.json and shells
out to `git merge-base main HEAD`. Under the old `push` trigger the checkout
took no `ref:`, so it checked out refs/heads/main and created a local `main`
branch as a side effect. That side effect, not anything deliberate, is what
made the command work; three nightlies published on top of it.

`workflow_run` requires an explicit `ref:` — an empty one silently falls back
to the default branch — but checking out a bare sha lands in detached HEAD
with no branches, so `main` stopped resolving. Reproduced outside CI with
`git fetch --depth=1 origin <sha>` + `git checkout --detach FETCH_HEAD`,
which yields exactly `fatal: Not a valid object name main`.

Pointing `main` at HEAD is not an approximation of the previous behavior, it
is that behavior: on a push to main the checked-out commit and the branch were
the same commit, so merge-base returned HEAD then too. getChangedPackagesSinceRef
was already a no-op here and stays one — the `releases` array this step is read
for comes from the .changeset/*.md files, not from a git diff.

`fetch-depth: 0` is the obvious wrong fix and the comment says so: a bare
`main` does not resolve through a remote-tracking ref, so it would buy a full
clone on every run and still fail.

This is the failure mode #132 called out as structurally unverifiable before
merge — workflow_run loads the workflow from the default branch, so no pull
request could exercise it. It failed closed rather than publishing something
unvalidated.

The breadcrumb job's unpinned checkout is a separate defect, fixed in #137.

Refs #127
Refs #131

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
#133 and #132 crossed. The nightly moved to `workflow_run` in #132, where
every checkout must carry `ref: github.event.workflow_run.head_sha`; the
`breadcrumb` job added by #133 was written against the `push` trigger and
merged without it.

Under `workflow_run` that is not an error. `github.sha` is the default branch
tip at event time, so the job checks out whatever `main` had moved to and
succeeds — running a copy of nightly-breadcrumb.cjs that Validate never saw,
while announcing a nightly built from a different commit. An empty `ref:`
fails the same way, silently, which is why the other two jobs assert HEAD
rather than trusting the checkout.

Cosmetic output does not lower the bar: it is the same fail-open shape, and
it reads as a normal green run. The job now pins the ref and asserts HEAD
against it, matching gate and publish line for line.

Nothing else moves. `breadcrumb` still reaches gate 0 transitively — a skipped
`gate` skips `publish`, which skips this — so it restates none of those four
conditions, and it consumes the publish job's stamped version rather than
re-deriving a short sha.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jwc9FFroR3mTZ4hLiSkkX3
@thecodedrift
thecodedrift force-pushed the fix/breadcrumb-workflow-run-ref branch from d8fbe96 to 17b2206 Compare August 21, 2026 17:33
@thecodedrift
thecodedrift merged commit 819465f into main Aug 21, 2026
2 checks passed
@thecodedrift
thecodedrift deleted the fix/breadcrumb-workflow-run-ref branch August 21, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changeset PR intentionally ships no release note (bypasses the changeset requirement)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants