Skip to content

[BUG] Mutation gate fails pull requests: stale-head checkout and missing root vitest binary #1498

Description

@edelauna

Problem (one or two sentences)

The mutation-diff job fails on any pull request whose head predates the mutation gate. The job dies on a missing script, not on surviving mutants.

Failing run: https://github.com/Zoo-Code-Org/Zoo-Code/actions/runs/33711419999/job/100511541034

Context (who is affected and when)

Every open pull request that branched off main before #1479 merged the gate. Each one fails Changed-code mutation testing until it rebases.

Root cause

  1. PR [Chore] Require changed-code mutation tests before review #1479 merged .github/workflows/mutation-testing.yml onto main.
  2. GitHub fires pull_request workflows from the merge ref. Main contains the workflow, so the gate triggers for old PR heads too.
  3. The checkout step pins ref: ${{ github.event.pull_request.head.sha }}. The job checks out the PR head, not the merge result.
  4. On an old head, package.json has no test:mutation-ci script and scripts/stryker-diff.mjs does not exist.
  5. The job fails: ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL Command "test:mutation-ci" not found, exit 254.

The gate tests the bare PR head instead of the code that would land. A stale branch fails on a missing script before mutation testing even starts.

Suggested fix

Check out the merge ref instead of the head:

- name: Checkout pull request merge result
  if: github.event_name == 'pull_request'
  uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
  with:
      ref: refs/pull/${{ github.event.pull_request.number }}/merge
      fetch-depth: 0
      persist-credentials: false

Notes:

  • With fetch-depth: 0 the merge commit carries both parents. --base and --head still resolve, and the diff still isolates the PR's own changed lines.
  • The merge ref lives on the base repo, so the step must drop repository:. This also fixes fork PRs.
  • A PR with conflicts against main has no merge ref. Checkout fails with a clear signal. That is correct, because the PR cannot merge anyway.

Rejected alternative: skip with exit 0 when the script is missing. That silently disables the gate for exactly the PRs most in need of it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions