Skip to content

fix: address Phase 2 review findings from #1819 #496

fix: address Phase 2 review findings from #1819

fix: address Phase 2 review findings from #1819 #496

Workflow file for this run

name: PR Body Check
on:
pull_request:
# `synchronize` is REQUIRED: the golden-fixture gate below is diff-dependent
# (it inspects the PR's changed files). Without `synchronize` the workflow
# would not re-run when a load-bearing fixture is pushed AFTER the PR opens,
# leaving a stale green — the exact wrong-trigger trap the enforcer-wiring
# gate (task 011) fences. The `synchronize` addition is likewise asserted by
# that gate for check-golden-fixture-note (diffDependent: true).
types: [opened, edited, synchronize, ready_for_review, reopened]
permissions:
contents: read
pull-requests: read
jobs:
validate-pr-body:
if: |
(github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request') &&
github.event.pull_request.user.login != 'renovate[bot]' &&
github.event.pull_request.user.login != 'dependabot[bot]' &&
!startsWith(github.event.pull_request.title, '[Graphite MQ]')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup GitHub CLI
env:
GH_VERSION: '2.65.0'
run: |
if ! command -v gh &>/dev/null; then
curl -fsSL "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_amd64.tar.gz" \
| tar xz -C /tmp
echo "/tmp/gh_${GH_VERSION}_linux_amd64/bin" >> "$GITHUB_PATH"
fi
- name: Validate PR body
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR="${{ github.event.pull_request.number }}"
BODY="$(gh pr view "$PR" --json body -q .body)"
# Determine required sections from template or defaults
if [[ -f ".exarchos/pr-template.md" ]]; then
SECTIONS=()
while IFS= read -r line; do
if [[ "$line" =~ ^##[[:space:]]+(.+)$ ]]; then
trimmed="${BASH_REMATCH[1]}"
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
SECTIONS+=("$trimmed")
fi
done < .exarchos/pr-template.md
else
SECTIONS=("Summary" "Changes" "Test Plan")
fi
# Safeguard: if template exists but yielded no sections, fall back to defaults
if [[ ${#SECTIONS[@]} -eq 0 ]]; then
echo "Warning: .exarchos/pr-template.md has no ## headings, using defaults"
SECTIONS=("Summary" "Changes" "Test Plan")
fi
# Escape regex metacharacters in section names
escape_ere() { printf '%s' "$1" | sed 's/[.[*^$()+?{|\\]/\\&/g'; }
MISSING=()
for section in "${SECTIONS[@]}"; do
escaped="$(escape_ere "$section")"
if ! printf '%s\n' "$BODY" | grep -qiE "^##[[:space:]]+${escaped}[[:space:]]*$"; then
MISSING+=("$section")
fi
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
echo "PR body validation failed."
for s in "${MISSING[@]}"; do
echo " Missing: ## $s"
done
echo ""
echo "Required sections: ${SECTIONS[*]}"
exit 1
fi
echo "PR body validation passed."
# Golden-fixture PR-body marker (DR-15, task 011). Diff-dependent gate:
# if this PR changes a file under
# tests/core/fixtures/load-bearing/**, the PR body MUST
# carry a `GOLDEN-FIXTURE-UPDATE: <reason>` line. Hosted here (not in the
# path-filtered ci.yml jobs) because it needs the PR body; the
# `synchronize` trigger above is what lets it re-run when a fixture is
# pushed after the PR opens. Zero-dependency node script — no install.
- name: Golden-fixture marker check (DR-15)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR="${{ github.event.pull_request.number }}"
gh pr view "$PR" --json body -q .body > "$RUNNER_TEMP/pr-body.txt"
# Use the paginated "list PR files" API, not `gh pr diff` — the .diff
# endpoint caps at 300 files and 406s on large PRs (e.g. the debloat
# wave itself), which would fail this gate closed on scale. The files
# API paginates (100/page) and returns the same newline-separated list.
gh api --paginate "repos/${{ github.repository }}/pulls/$PR/files" \
--jq '.[].filename' > "$RUNNER_TEMP/pr-changed.txt"
node tools/audit/gates/check-golden-fixture-note.mjs \
--body-file "$RUNNER_TEMP/pr-body.txt" \
--changed-files-file "$RUNNER_TEMP/pr-changed.txt"