From 27c24cd060a8a4d771e2c706151407c4e54e359e Mon Sep 17 00:00:00 2001 From: Jakob Heuser Date: Sat, 13 Jun 2026 09:51:04 -0700 Subject: [PATCH] ci(openspec): Skip the archive check on non-tip stacked PRs Bring the stack-aware OpenSpec archive check (originally #31, landed in the local-rule-routing stack) into the telemetry stack so PRs below the tip show the check as skipped and only the tip runs it. Identical content to the local-rule-routing copy, so the two stacks won't conflict when both reach main. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/pr-check-openspec.yml | 44 +++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-check-openspec.yml b/.github/workflows/pr-check-openspec.yml index 40395f37..e1cf7ebe 100644 --- a/.github/workflows/pr-check-openspec.yml +++ b/.github/workflows/pr-check-openspec.yml @@ -1,14 +1,52 @@ name: PR OpenSpec Archive Check +# A change is archived exactly once, when ALL of its work has landed. In a +# stack of PRs, only the tip carries the archived change; the PRs below it still +# carry the in-flight change directory by design. So this check runs only on the +# tip of a stack (or a standalone PR) and is skipped on PRs that still have work +# stacked on top of them. Tip = no other OPEN PR targets this PR's head branch +# as its base. on: pull_request: - branches: [main] permissions: contents: read + pull-requests: read jobs: + stack-position: + name: Detect stack position + runs-on: ubuntu-latest + outputs: + is_tip: ${{ steps.detect.outputs.is_tip }} + steps: + - name: Determine whether this PR is the tip of its stack + id: detect + env: + GH_TOKEN: ${{ github.token }} + HEAD_REF: ${{ github.head_ref }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + + # Count OPEN PRs that target this PR's head branch as their base. + # Any such PR means work is still stacked on top → not the tip. + children=$(gh pr list --repo "$REPO" --state open --base "$HEAD_REF" \ + --json number --jq 'length' 2>/dev/null || echo 0) + children=${children:-0} + + if [ "$children" -gt 0 ]; then + echo "is_tip=false" >> "$GITHUB_OUTPUT" + echo "This PR has $children open PR(s) stacked on top — changes still in flight." + echo "The OpenSpec archive check is skipped until this PR is the tip of the stack." + else + echo "is_tip=true" >> "$GITHUB_OUTPUT" + echo "No PRs are stacked on top — this PR is the tip (or standalone); the archive check will run." + fi + check-openspec-archived: + needs: stack-position + if: needs.stack-position.outputs.is_tip == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 @@ -28,8 +66,8 @@ jobs: echo "::error::Unarchived OpenSpec change directories found under openspec/changes/:" echo "$UNARCHIVED" | sed 's|^| - |' echo "" - echo "Every change must be moved under openspec/changes/archive/ before merge." - echo "Run the openspec archive workflow (e.g. /openspec-archive-change ) and commit the result." + echo "This PR is the tip of its stack (all work landed), so the change must be archived." + echo "Move it under openspec/changes/archive/ (e.g. /openspec-archive-change ) and commit." exit 1 fi