From fcb2049f3f4a7daa1621dada8a106082d35b32d3 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Wed, 29 Apr 2026 15:44:07 -0700 Subject: [PATCH] ci: add no-op shadow for Canvas (Next.js) required check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PRs that don't touch canvas/** paths skip the Canvas (Next.js) job via its `if: needs.changes.outputs.canvas == 'true'` guard. GitHub reports SKIPPED for that conclusion. Branch protection on staging requires Canvas (Next.js) — and treats SKIPPED as not-passed, blocking merge on every workspace-server-only or migration-only PR. This is the design pattern documented in feedback memory "branch_protection_check_name_parity": split into a real job + a no-op shadow that share the same `name:`. Exactly one runs per PR; both report the same check context, and at least one always reports SUCCESS, satisfying the required check. The no-op job runs in a few seconds (single `echo` step) and produces the right check context for any PR that has changes outside canvas/**. Concrete blocker that prompted this: PR #2314 (RFC #2312 PR-B) sat APPROVED + CI-green + UP-TO-DATE for half an hour with mergeStateStatus BLOCKED, traced via the GraphQL `isRequired` field to a single SKIPPED Canvas (Next.js) check. PRs #2319 (PR-F) and the rest of the RFC #2312 stack would have hit the same wall. --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e3ae250..f13c16ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,6 +178,26 @@ jobs: exit 1 fi + # Path-filter no-op shadow for Canvas (Next.js). + # + # Branch protection on staging requires a "Canvas (Next.js)" check. + # When a PR doesn't touch canvas/** paths, the real canvas-build job + # below is skipped via `if:`, and GitHub reports its conclusion as + # SKIPPED — which branch protection treats as not-passed → merge + # BLOCKED on every workspace-server-only or migration-only PR. + # + # Pattern (per durable feedback memory: branch_protection_check_name_parity): + # split into a real job + a no-op shadow that share the same `name:`. + # Exactly one runs per PR; both report the same check context, and at + # least one always reports SUCCESS, satisfying the required check. + canvas-build-noop: + name: Canvas (Next.js) + needs: changes + if: needs.changes.outputs.canvas != 'true' + runs-on: ubuntu-latest + steps: + - run: echo "No canvas/** changes in this PR — Canvas (Next.js) skip is intentional, satisfying required-check via this no-op." + canvas-build: name: Canvas (Next.js) needs: changes