Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
537 changes: 537 additions & 0 deletions .copilot/skills/pr-lifecycle/SKILL.md

Large diffs are not rendered by default.

408 changes: 159 additions & 249 deletions .github/workflows/squad-ci.yml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .github/workflows/squad-docs-links.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ name: Docs — Weekly Link Check
on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true

jobs:
linkcheck:
runs-on: ubuntu-latest
Expand Down
23 changes: 4 additions & 19 deletions .github/workflows/squad-insider-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,15 @@ on:
branches:
- insider

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
node-version: [22]
steps:
- uses: actions/checkout@v4

# CI Hardening: Composite action replaces duplicated setup-node + retry
# pattern (item 7). See .github/actions/setup-squad-node/action.yml.
- uses: ./.github/actions/setup-squad-node
with:
node-version: ${{ matrix.node-version }}

- name: Build
run: npm run build

test:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/squad-insider-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
branches: [insider]

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
contents: write

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/squad-npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ on:
description: 'Version to publish (e.g., 0.9.1)'
required: true
type: string

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
id-token: write
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/squad-pr-readiness.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ name: Squad PR Readiness
on:
pull_request_target:
branches: [dev, main, insider]
types: [opened, synchronize, reopened, edited, ready_for_review]
# opened + synchronize + reopened removed: redundant with workflow_run
# trigger (Squad CI fires on those events, then workflow_run fires PR readiness)
types: [edited, ready_for_review]
workflow_run:
workflows: ["Squad CI"]
types: [completed]
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/squad-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
branches: [preview]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/squad-promote.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ on:
type: choice
options: ['false', 'true']

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
contents: write

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/squad-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
branches: [main]

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false

permissions:
contents: write

Expand Down
161 changes: 78 additions & 83 deletions .github/workflows/squad-repo-health.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,36 @@ concurrency:
cancel-in-progress: true

jobs:
# ─── Bootstrap Protection (BLOCKING) ────────────────────────────────
bootstrap-protection:
name: Bootstrap Protection
# ═══════════════════════════════════════════════════════════════════════
# Consolidated repo-health job — runs all checks on a single runner.
# Each check is a step with if: always() so all checks run even if
# one fails. Saves ~4 runner boots per PR push vs separate jobs.
# ═══════════════════════════════════════════════════════════════════════
repo-health:
name: Repo Health
runs-on: ubuntu-latest
timeout-minutes: 3
timeout-minutes: 10
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: |
scripts/check-bootstrap-deps.mjs
sparse-checkout-cone-mode: false
fetch-depth: 0

- name: Fetch PR head (data only — not executed)
run: git fetch origin ${{ github.event.pull_request.head.sha }}
run: |
git fetch origin ${{ github.event.pull_request.head.sha }}
git fetch origin dev --quiet

- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Check bootstrap dependencies

# ─── Bootstrap Protection (BLOCKING) ──────────────────────────────
- name: "Check: Bootstrap Protection"
id: bootstrap
if: always()
run: |
echo "## 🔒 Bootstrap Protection" >> $GITHUB_STEP_SUMMARY
set +e
OUTPUT=$(node scripts/check-bootstrap-deps.mjs --ref ${{ github.event.pull_request.head.sha }} 2>&1)
EXIT_CODE=$?
Expand All @@ -45,142 +55,127 @@ jobs:
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
if [ "$EXIT_CODE" -eq 0 ]; then
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Failed" >> $GITHUB_STEP_SUMMARY
fi
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit $EXIT_CODE

# ─── Diff Size Guard (WARNING) ─────────────────────────────────────
diff-guard:
name: Diff Size Guard
runs-on: ubuntu-latest
timeout-minutes: 2
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch PR head (data only — not executed)
run: git fetch origin ${{ github.event.pull_request.head.sha }}
- name: Check for likely contamination
# ─── Diff Size Guard (WARNING) ────────────────────────────────────
- name: "Check: Diff Size Guard"
if: always()
run: |
git fetch origin dev --quiet
echo "## 📏 Diff Size Guard" >> $GITHUB_STEP_SUMMARY
FILE_COUNT=$(git diff --name-only origin/dev...${{ github.event.pull_request.head.sha }} | wc -l)
COMMIT_COUNT=$(git rev-list --count origin/dev..${{ github.event.pull_request.head.sha }})

# Heuristic: if a single-commit PR touches more than 30 files, it's likely contaminated
if [ "$COMMIT_COUNT" -le 2 ] && [ "$FILE_COUNT" -gt 30 ]; then
echo "::warning::⚠️ This PR has $COMMIT_COUNT commit(s) but touches $FILE_COUNT files."
echo "::warning::This may indicate branch contamination from broad staging (--all or .) on a stale branch."
echo "::warning::Please verify all changed files are intentional: git diff --name-only origin/dev...${{ github.event.pull_request.head.sha }}"
echo "⚠️ Warning: $COMMIT_COUNT commit(s) but $FILE_COUNT file(s) — possible contamination" >> $GITHUB_STEP_SUMMARY
else
echo "✅ Diff looks proportional: $COMMIT_COUNT commit(s), $FILE_COUNT file(s)."
echo "✅ Diff looks proportional: $COMMIT_COUNT commit(s), $FILE_COUNT file(s)." >> $GITHUB_STEP_SUMMARY
fi

# ─── Squad File Leakage (WARNING) ───────────────────────────────────
squad-leakage:
name: Squad File Leakage
runs-on: ubuntu-latest
timeout-minutes: 3
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch PR head (data only — not executed)
run: git fetch origin ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Detect .squad/ leakage
# ─── Squad File Leakage (WARNING) ─────────────────────────────────
- name: "Check: Squad File Leakage"
id: leakage
if: always()
run: |
git fetch origin dev --quiet
echo "## 🔍 Squad File Leakage" >> $GITHUB_STEP_SUMMARY
echo "result<<EOF" >> $GITHUB_OUTPUT
echo "(no output)" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
OUTPUT=$(node scripts/check-squad-leakage.mjs origin/dev ${{ github.event.pull_request.head.sha }} 2>&1)
echo "$OUTPUT"
echo "result<<EOF" >> $GITHUB_OUTPUT
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Comment on leakage
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

- name: "Comment: Leakage"
if: always()
uses: actions/github-script@v7
env:
LEAKAGE_OUTPUT: ${{ steps.leakage.outputs.result }}
with:
script: |
const { run } = await import(`${process.env.GITHUB_WORKSPACE}/scripts/repo-health-comment.mjs`);
await run({
github,
context,
output: `${{ steps.leakage.outputs.result }}`,
output: process.env.LEAKAGE_OUTPUT ?? '',
job: 'leakage',
});
Comment thread
diberry marked this conversation as resolved.

# ─── Architectural Review (INFORMATIONAL) ───────────────────────────
architectural-review:
name: Architectural Review — Structure & Design Rules
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch PR head (data only — not executed)
run: git fetch origin ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Run architectural review
# ─── Architectural Review (INFORMATIONAL) ─────────────────────────
- name: "Check: Architectural Review"
id: arch
if: always()
run: |
git fetch origin dev --quiet
echo "## 🏗️ Architectural Review" >> $GITHUB_STEP_SUMMARY
echo "result<<EOF" >> $GITHUB_OUTPUT
echo "(no output)" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
OUTPUT=$(node scripts/architectural-review.mjs origin/dev ${{ github.event.pull_request.head.sha }} 2>&1)
echo "$OUTPUT"
echo "result<<EOF" >> $GITHUB_OUTPUT
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Comment on findings
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

- name: "Comment: Architectural Review"
if: always()
uses: actions/github-script@v7
env:
ARCH_OUTPUT: ${{ steps.arch.outputs.result }}
with:
script: |
const { run } = await import(`${process.env.GITHUB_WORKSPACE}/scripts/repo-health-comment.mjs`);
await run({
github,
context,
output: `${{ steps.arch.outputs.result }}`,
output: process.env.ARCH_OUTPUT ?? '',
job: 'architectural',
});

Comment thread
diberry marked this conversation as resolved.
# ─── Security Review (INFORMATIONAL) ────────────────────────────────
security-review:
name: Security Review — Permissions & Secrets
runs-on: ubuntu-latest
timeout-minutes: 5
if: github.actor != 'dependabot[bot]'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch PR head (data only — not executed)
run: git fetch origin ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Run security review
# ─── Security Review (INFORMATIONAL) ──────────────────────────────
- name: "Check: Security Review"
id: security
if: always()
run: |
git fetch origin dev --quiet
echo "## 🔐 Security Review" >> $GITHUB_STEP_SUMMARY
echo "result<<EOF" >> $GITHUB_OUTPUT
echo "(no output)" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
OUTPUT=$(node scripts/security-review.mjs origin/dev ${{ github.event.pull_request.head.sha }} 2>&1)
echo "$OUTPUT"
echo "result<<EOF" >> $GITHUB_OUTPUT
echo "$OUTPUT" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Comment on findings
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$OUTPUT" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

- name: "Comment: Security Review"
if: always()
uses: actions/github-script@v7
env:
SECURITY_OUTPUT: ${{ steps.security.outputs.result }}
with:
script: |
const { run } = await import(`${process.env.GITHUB_WORKSPACE}/scripts/repo-health-comment.mjs`);
await run({
github,
context,
output: `${{ steps.security.outputs.result }}`,
output: process.env.SECURITY_OUTPUT ?? '',
job: 'security',
});
4 changes: 4 additions & 0 deletions .github/workflows/squad-scope-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ permissions:
pull-requests: read
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
scope-boundary:
name: "Scope Boundary"
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/sync-squad-labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
- '.ai-team/team.md'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true

permissions:
issues: write
contents: read
Expand Down
2 changes: 0 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,6 @@ An automated readiness check runs on every PR and posts a checklist comment. Add
| **No merge conflicts** | Resolve any conflicts with the target branch |
| **CI passing** | All CI checks (build, test, lint) must be green |

The readiness comment also includes a **file list with line stats** — each changed file is shown with per-file addition/deletion counts, a scope classification (Product/Infrastructure/Mixed), and totals. This helps reviewers quickly gauge PR size and impact.

The readiness check is **informational** — it helps you self-serve before a human reviewer looks at your PR. It automatically re-runs after Squad CI completes, so the checklist stays up to date without manual intervention. See `.github/PR_REQUIREMENTS.md` for the full requirements spec.

## Code Style & Conventions
Expand Down
Loading
Loading