From 7bfca27f2b0df8d7945e08a272b5e6f5c3cb590c Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sun, 14 Jun 2026 02:17:37 +0100 Subject: [PATCH] ## What Fix a required-status-check deadlock by converting the path-filtered required job to a **pass-through shim** (same pattern as echidna#256). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why This job is a **required** status check but its workflow is path-filtered on `pull_request`, so it never runs (never reports) on PRs that don't touch those paths — branch protection then waits forever and the PR can't merge via normal flow. ## Fix - Drop the `pull_request` paths-filter so the job **always runs** (the required check always reports). - A `Detect relevant changes` step reads the PR's changed files via the GitHub API and gates the heavy steps — real work runs only when the relevant sources change; otherwise it passes through in seconds. - `push` stays scoped to the default branch + paths (post-merge behaviour unchanged); job names preserved so the required contexts still match. Identified by the 2026-06-14 estate required-check deadlock audit (`dev-notes/audits/`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- .github/workflows/elixir-ci.yml | 55 +++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/.github/workflows/elixir-ci.yml b/.github/workflows/elixir-ci.yml index df65d2d..addbd5b 100644 --- a/.github/workflows/elixir-ci.yml +++ b/.github/workflows/elixir-ci.yml @@ -6,11 +6,12 @@ on: paths: - 'elixir-mcp/**' - '.github/workflows/elixir-ci.yml' + # No pull_request paths-filter: Dialyzer is a REQUIRED status check, so it must + # report on every PR (a path-filtered required check deadlocks PRs that don't + # touch its paths). The "Detect relevant changes" step gates the heavy work; the + # non-required test matrix is gated the same way so it doesn't run on every PR. pull_request: branches: [main] - paths: - - 'elixir-mcp/**' - - '.github/workflows/elixir-ci.yml' permissions: contents: read jobs: @@ -20,6 +21,7 @@ jobs: timeout-minutes: 15 permissions: contents: read + pull-requests: read # change-detector reads the PR's file list defaults: run: working-directory: elixir-mcp @@ -29,12 +31,32 @@ jobs: otp: ['26'] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Detect relevant changes + id: detect + working-directory: ${{ github.workspace }} + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + PATTERN='^elixir-mcp/' + if [ "${{ github.event_name }}" = "pull_request" ]; then + FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[].filename') + if printf '%s\n' "$FILES" | grep -qE "$PATTERN"; then + echo "relevant=true" >> "$GITHUB_OUTPUT" + else + echo "relevant=false" >> "$GITHUB_OUTPUT"; echo "No elixir-mcp changes — pass-through (required-check shim)." + fi + else + echo "relevant=true" >> "$GITHUB_OUTPUT" + fi - name: Set up Elixir + if: steps.detect.outputs.relevant == 'true' uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0 with: elixir-version: ${{ matrix.elixir }} otp-version: ${{ matrix.otp }} - name: Cache deps + if: steps.detect.outputs.relevant == 'true' uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | @@ -44,12 +66,16 @@ jobs: restore-keys: | mix-${{ matrix.elixir }}-${{ matrix.otp }}- - name: Install dependencies + if: steps.detect.outputs.relevant == 'true' run: mix deps.get - name: Compile (warnings as errors) + if: steps.detect.outputs.relevant == 'true' run: mix compile --warnings-as-errors - name: Check formatting + if: steps.detect.outputs.relevant == 'true' run: mix format --check-formatted - name: Run tests + if: steps.detect.outputs.relevant == 'true' run: mix test --trace dialyzer: name: Dialyzer @@ -57,17 +83,38 @@ jobs: timeout-minutes: 15 permissions: contents: read + pull-requests: read # change-detector reads the PR's file list defaults: run: working-directory: elixir-mcp steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Detect relevant changes + id: detect + working-directory: ${{ github.workspace }} + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + PATTERN='^elixir-mcp/' + if [ "${{ github.event_name }}" = "pull_request" ]; then + FILES=$(gh api "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --paginate --jq '.[].filename') + if printf '%s\n' "$FILES" | grep -qE "$PATTERN"; then + echo "relevant=true" >> "$GITHUB_OUTPUT" + else + echo "relevant=false" >> "$GITHUB_OUTPUT"; echo "No elixir-mcp changes — pass-through (required-check shim)." + fi + else + echo "relevant=true" >> "$GITHUB_OUTPUT" + fi - name: Set up Elixir + if: steps.detect.outputs.relevant == 'true' uses: erlef/setup-beam@fc68ffb90438ef2936bbb3251622353b3dcb2f93 # v1.24.0 with: elixir-version: '1.17' otp-version: '26' - name: Cache deps + if: steps.detect.outputs.relevant == 'true' uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | @@ -77,7 +124,9 @@ jobs: restore-keys: | dialyzer- - name: Install dependencies + if: steps.detect.outputs.relevant == 'true' run: mix deps.get - name: Run Dialyzer + if: steps.detect.outputs.relevant == 'true' run: mix dialyzer continue-on-error: true