name: PR Pipeline — Validate → Review → Merge on: pull_request: types: [opened, synchronize, reopened] paths: - '**.prose.md' jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: YAML frontmatter validation run: | echo "=== Prose Contract Frontmatter Validation ===" FAILED=0 for f in $(find . -name "*.prose.md" -not -path "./.git/*" -not -path "./runs/*"); do FM=$(sed -n '/^---$/,/^---$/p' "$f" | sed '1d;$d') [ -z "$FM" ] && { echo " ❌ $f: No YAML frontmatter"; FAILED=1; continue; } KIND=$(echo "$FM" | grep '^kind:' | awk '{print $2}') case "$KIND" in function|responsibility|gateway|pattern|test|template|architecture) echo " ✅ $f: kind=$KIND" ;; *) echo " ❌ $f: Invalid kind='$KIND'"; FAILED=1 ;; esac echo "$FM" | grep -q '^name:' || { echo " ❌ $f: Missing name"; FAILED=1; } echo "$FM" | grep -q '^description:' || { echo " ❌ $f: Missing description"; FAILED=1; } done [ $FAILED -eq 1 ] && { echo "❌ FRONTMATTER FAILED"; exit 1; } echo "✅ Frontmatter validation passed" lint: runs-on: ubuntu-latest needs: validate steps: - uses: actions/checkout@v4 - name: Structure + regression lint run: bash scripts/prose-lint.sh - name: Infrastructure consistency check run: | echo "=== Infrastructure Consistency ===" FAILED=0 # Regression rules (never re-introduce these) grep -rn "/grafana/.*harness-grafana\|location.*\/grafana\/" *.prose.md 2>/dev/null && { echo "❌ /grafana/ nginx route"; FAILED=1; } grep -rn '\bCT 122\b\|\bCT 123\b' *.prose.md 2>/dev/null && { echo "❌ Stale CT 122/123"; FAILED=1; } grep -rn '\.19.*Zulip\|Zulip.*\.19\|192\.168\.68\.19' *.prose.md 2>/dev/null && { echo "❌ Stale .19 IP"; FAILED=1; } STRIX=$(grep -rn "192\.168\.68\.15:8080\|\.15:8080\b" *.prose.md 2>/dev/null | grep -v "firewalled\|firewall\|:116 only" || true) [ -n "$STRIX" ] && { echo "❌ Strix :8080 without firewall note: $STRIX"; FAILED=1; } [ $FAILED -eq 0 ] && echo "✅ Consistency check passed" || { echo "❌ FAILED"; exit 1; } echo "✅ Consistency OK" ai-review: runs-on: ubuntu-latest needs: validate steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: AI-powered contract review env: LITELLM_URL: ${{ secrets.LITELLM_URL }} LITELLM_KEY: ${{ secrets.LITELLM_KEY }} run: bash scripts/prose-ai-review.sh auto-merge: runs-on: ubuntu-latest needs: [validate, lint, ai-review] if: success() steps: - name: Merge PR run: | echo "All checks passed. Merging..." # Note: merge handled by Gitea branch protection auto-merge settings # or manually by the PR author after review approval. # This job serves as a gate — when all checks are green, merge is safe. echo "✅ PR is safe to merge. Awaiting branch protection or manual merge."