Skip to content
Closed
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
84 changes: 43 additions & 41 deletions .copilot/mcp-config.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,16 @@
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
},
"mongodb": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"mongodb-mcp-server"
"mongodb-mcp-server@latest"
],
"env": {
"MDB_MCP_CONNECTION_STRING": "${MONGODB_CONNECTION_STRING}"
}
"gallery": true
},
"azure": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
Expand All @@ -33,38 +19,54 @@
"start"
]
},
"playwright": {
"github/github-mcp-server": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"gallery": "https://api.mcp.github.com/2025-09-15",
"version": "0.13.0"
},
"microsoft/playwright-mcp": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest"
]
],
"gallery": "https://api.mcp.github.com/2025-09-15",
"version": "0.0.1-seed"
},
"docker": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/var/run/docker.sock:/var/run/docker.sock",
"mcp/docker"
]
"microsoftdocs/mcp": {
"type": "http",
"url": "https://learn.microsoft.com/api/mcp",
"gallery": "https://api.mcp.github.com/2025-09-15",
"version": "1.0.0"
},
"filesystem": {
"io.github.upstash/context7": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"."
]
"@upstash/context7-mcp@1.0.31"
],
"env": {
"CONTEXT7_API_KEY": "${input:CONTEXT7_API_KEY}"
},
"gallery": "https://api.mcp.github.com",
"version": "1.0.31"
},
"fetch": {
"sequentialthinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-fetch"
]
"@modelcontextprotocol/server-sequential-thinking"
],
"type": "stdio"
}
},
"inputs": [
{
"id": "CONTEXT7_API_KEY",
"type": "promptString",
"description": "API key for authentication",
"password": true
}
}
}
]
}
2 changes: 2 additions & 0 deletions .copilot/skills/ci-validation-gates/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ confidence: "high"
source: "extracted from Drucker and Trejo charters — earned knowledge from v0.8.22 release incident"
---

> ⚠️ **Squad CLI Only** — This skill documents npm/CI patterns from the Squad CLI project (v0.8.22 incident). It is NOT applicable to IssueTrackerApp (.NET/Blazor). For IssueTrackerApp CI gates, see `.github/hooks/pre-push` and `.squad/playbooks/pre-push-process.md`.

## Context

CI workflows must be defensive. These patterns were learned from the v0.8.22 release disaster where invalid semver, wrong token types, missing retry logic, and draft releases caused a multi-hour outage. Both Drucker (CI/CD) and Trejo (Release Manager) carried this knowledge in their charters — now centralized here.
Expand Down
29 changes: 11 additions & 18 deletions .copilot/skills/git-workflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ source: "team-decision"

## Context

Squad uses a three-branch model. **All feature work starts from `dev`, not `main`.**
Squad uses a two-branch model. **All feature work starts from `dev`, not `main`.**

| Branch | Purpose | Publishes |
|--------|---------|-----------|
| `main` | Released, tagged, in-npm code only | `npm publish` on tag |
| `dev` | Integration branch — all feature work lands here | `npm publish --tag preview` on merge |
| `insiders` | Early-access channel — synced from dev | `npm publish --tag insiders` on sync |
| `main` | Released, tagged code only | GitHub Release on tag (via `squad-milestone-release`) |
| `dev` | Integration branch — all feature work lands here | Preview builds via `squad-preview` on merge |

## Branch Naming Convention

Expand Down Expand Up @@ -161,22 +160,16 @@ Each repo gets its own issue branch following its own naming convention. If the

### Local Linking for Testing

Before pushing, verify cross-repo changes work together:
Before pushing, verify cross-project changes work together:

```bash
# Node.js / npm
cd ../squad-sdk && npm link
cd ../squad-pr && npm link squad-sdk

# Go
# Use replace directive in go.mod:
# replace github.com/org/squad-sdk => ../squad-sdk

# Python
cd ../squad-sdk && pip install -e .
# .NET — use project references in solution for local testing
# In the dependent project's .csproj, temporarily use:
# <ProjectReference Include="../../squad-sdk/src/SdkProject.csproj" />
# Revert to PackageReference before committing.
```

**Important:** Remove local links before committing. `npm link` and `go replace` are dev-only — CI must use published packages or PR-specific refs.
**Important:** Remove local project references before committing. CI must use published NuGet packages or PR-specific refs.

### Worktrees + Multi-Repo

Expand All @@ -199,6 +192,6 @@ These compose naturally. You can have:

## Promotion Pipeline

- dev → insiders: Automated sync on green build
- devmain: Manual merge when ready for stable release, then tag
- dev → main: Manual promotion via `squad-promote` workflow (opens a PR from dev → main), then merge
- mainrelease: Tag on main via `squad-milestone-release` workflow, creates GitHub Release
- Hotfixes: Branch from main as `hotfix/{slug}`, PR to dev, cherry-pick to main if urgent
12 changes: 6 additions & 6 deletions .copilot/skills/merged-pr-guard/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
`high`

## Problem
When an agent or Scribe attempts to commit to a `squad/*` branch whose PR has already been merged, the commit either targets a deleted/stale branch or diverges from `main`. This causes stranded commits and orphaned history.
When an agent or Scribe attempts to commit to a `squad/*` branch whose PR has already been merged, the commit either targets a deleted/stale branch or diverges from `dev`. This causes stranded commits and orphaned history.

## Solution
Before any `git commit` on a `squad/*` branch, check whether that branch's PR has been merged. If merged, sync to `main` first.
Before any `git commit` on a `squad/*` branch, check whether that branch's PR has been merged. If merged, sync to `dev` first.

## Pattern

Expand All @@ -16,9 +16,9 @@ CURRENT_BRANCH=$(git branch --show-current)
MERGED=$(gh pr list --head "$CURRENT_BRANCH" --state merged --json number --limit 1)

if [ -n "$MERGED" ] && [ "$MERGED" != "[]" ]; then
# PR is already merged — move to main
git checkout main
git pull origin main
# PR is already merged — move to dev (the active development branch)
git checkout dev
git pull origin dev
# now commit here instead
fi

Expand All @@ -35,5 +35,5 @@ git commit -F "$COMMIT_MSG_FILE"
`gh pr list --head {branch} --state merged` returns an empty array `[]` when no merged PR exists for that branch, and a populated array when one does. Non-empty + non-`[]` means the PR is merged.

## Observed In
- Session where Scribe committed `.squad/` changes to `squad/unit-tests-split` after PR #95 was merged — commit stranded on a re-created branch instead of flowing to `main`
- Session where Scribe committed `.squad/` changes to `squad/unit-tests-split` after PR #95 was merged — commit stranded on a re-created branch instead of flowing to `dev`
- Established as a standing process rule after PR #95/PR #96 session
117 changes: 56 additions & 61 deletions .copilot/skills/pre-push-test-gate/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,90 +1,85 @@
---
name: pre-push-test-gate
confidence: high
source: .github/hooks/pre-push
description: >
Enforces build cleanliness and test passage before any git push.
Delegates to the build-repair prompt (.github/prompts/build-repair.prompt.md)
as the authoritative gate. Established after the Shared project test batch
(04714a4) shipped two broken tests directly to main.
Knowledge skill documenting the 5-gate pre-push hook that enforces build
cleanliness and full test passage before any git push. The hook is installed
at .git/hooks/pre-push and mirrors CI gates locally.
---

## Pre-Push Test Gate

### Why This Exists
### Overview

On 2026-02-25, two unit tests were pushed directly to `main` without local verification.
Both tests had wrong expectations and failed in CI. This skill enforces the gate that
prevents that from recurring.
The pre-push hook (`.github/hooks/pre-push`) enforces **5 gates** that mirror CI. It runs automatically on every `git push` and blocks the push if any gate fails.

### The Gate
> 📋 **For the step-by-step execution playbook, see:** `.squad/playbooks/pre-push-process.md`

Before any `git push`, an agent MUST run the **Build Repair Skill**:
### The 5 Gates

> **`.github/prompts/build-repair.prompt.md`**
| Gate | Name | What It Does | Blocks If |
|------|------|-------------|-----------|
| **0** | Branch protection | Checks current branch | Push is to `main` or `dev` |
| **1** | Untracked source files | Scans for untracked `.razor`/`.cs` files | Untracked source files found (prompts y/N) |
| **2** | Release build | `dotnet build IssueTrackerApp.slnx --configuration Release` | Build fails (3 retries) |
| **3** | Unit/Arch/bUnit tests | Runs 6 test projects in Release mode | Any test project fails (3 retries) |
| **4** | Integration tests | Runs 4 integration test projects (Docker required) | Any test project fails (3 retries) |

That prompt already defines the full gate:
1. Restore dependencies (`dotnet restore`)
2. Build the solution (`dotnet build --no-restore`) — zero errors, zero warnings
3. Fix any build errors before continuing
4. Run unit tests — all must pass
5. Fix test failures before continuing
### Gate 3 — Unit Test Projects (6 total)

Only push when the build-repair prompt reports **"Build succeeded"** with **zero warnings**
and **all tests pass**.
```
tests/Architecture.Tests/Architecture.Tests.csproj
tests/Domain.Tests/Domain.Tests.csproj
tests/Web.Tests.Bunit/Web.Tests.Bunit.csproj
tests/Persistence.MongoDb.Tests/Persistence.MongoDb.Tests.csproj
tests/Web.Tests/Web.Tests.csproj
tests/Persistence.AzureStorage.Tests/Persistence.AzureStorage.Tests.csproj
```

### Agent Checklist
### Gate 4 — Integration Test Projects (4 total, Docker required)

Before any `git push`, an agent MUST:
```
tests/Persistence.MongoDb.Tests.Integration/Persistence.MongoDb.Tests.Integration.csproj
tests/Web.Tests.Integration/Web.Tests.Integration.csproj
tests/Persistence.AzureStorage.Tests.Integration/Persistence.AzureStorage.Tests.Integration.csproj
tests/AppHost.Tests/AppHost.Tests.csproj
```

- [ ] Open `.github/prompts/build-repair.prompt.md` and execute it fully
- [ ] Confirm final output: `Build succeeded. 0 Warning(s). 0 Error(s).`
- [ ] Confirm final test output: `Passed! Failed: 0`
- [ ] Only then execute `git push`
These use Testcontainers (mongo:7.0, Azurite) and Aspire DCP. Docker daemon MUST be running.

Do NOT push if either check reports failures. Fix first.
### Retry Behavior

### Hook (Local Enforcement)
Gates 2, 3, and 4 allow **3 attempts**. Between attempts the hook pauses and prompts:
> "Fix the errors and press Enter to retry, or Ctrl+C to abort"

The `.git/hooks/pre-push` hook runs unit tests as a local tripwire.
Install once per clone — **Shell (Linux/macOS/Git Bash)**:
### Hook Installation

The hook source is committed at `.github/hooks/pre-push`. Install once per clone:

```bash
cat > .git/hooks/pre-push << 'EOF'
#!/usr/bin/env bash
set -euo pipefail
echo "🔎 pre-push: running build-repair gate (Domain.Tests + Web.Tests)…"
if dotnet test tests/Domain.Tests tests/Web.Tests --configuration Release --verbosity quiet 2>&1; then
echo "✅ Gate passed — push allowed."
else
echo "❌ Gate FAILED. Run .github/prompts/build-repair.prompt.md and fix before pushing."
exit 1
fi
EOF
cp .github/hooks/pre-push .git/hooks/pre-push
chmod +x .git/hooks/pre-push
```

**PowerShell (Windows):**
```powershell
@'
#!/usr/bin/env bash
set -euo pipefail
echo "🔎 pre-push: running build-repair gate (Domain.Tests + Web.Tests)…"
if dotnet test tests/Domain.Tests tests/Web.Tests --configuration Release --verbosity quiet 2>&1; then
echo "✅ Gate passed — push allowed."
else
echo "❌ Gate FAILED. Run .github/prompts/build-repair.prompt.md and fix before pushing."
exit 1
fi
'@ | Set-Content -NoNewline .git/hooks/pre-push
```

> The hook is not committed — install on every fresh clone. The build-repair prompt
> is the authoritative process; the hook is a fast local tripwire.
> ⚠️ Do NOT create inline hook scripts. Always copy from `.github/hooks/pre-push` to get the full 5-gate version.

### Failure Taxonomy (known patterns)
### Failure Taxonomy (Known Patterns)

| Symptom | Root Cause | Fix |
|---------|-----------|-----|
| `DateTime` equality failure in `*.Empty` tests | `Empty` property calls `DateTime.UtcNow` each time — two calls produce different values | Assert individual fields, not whole-record equality |
| Unexpected trailing `_` in slug tests | `GenerateSlug` appends `_` when string ends with punctuation AND has internal punctuation | Verify actual output against implementation before asserting |
| Record equality fails on nested DTO | Nested DTO `Empty` also uses `UtcNow` — same root cause | Flatten assertions to field-level |
| Warning treated as error (Gate 2) | `TreatWarningsAsErrors=true` in Directory.Build.props | Fix the warning — do not suppress |
| Architecture test failure (Gate 3) | Naming convention violation | Commands → `Command`, queries → `Query`, handlers → `Handler` (must be `sealed`), validators → `Validator` |
| bUnit test failure (Gate 3) | API change in bUnit 2.x | Use `Render<T>()` not `RenderComponent<T>()` |
| `DateTime` equality failure (Gate 3) | `Empty` property calls `DateTime.UtcNow` each time | Assert individual fields, not whole-record equality |
| Docker not running (Gate 4) | Testcontainers can't start | `sudo systemctl start docker` or start Docker Desktop |
| Container timeout (Gate 4) | Slow image pull or low resources | Pre-pull `mongo:7.0`; increase Docker memory |
| Untracked `.razor`/`.cs` (Gate 1) | New files not staged | `git add <files>` before pushing |

### Related Documents

- **Hook source:** `.github/hooks/pre-push`
- **Execution playbook:** `.squad/playbooks/pre-push-process.md`
- **Build repair prompt:** `.github/prompts/build-repair.prompt.md`
- **Contributing guide:** `CONTRIBUTING.md` (Pre-Push Gates section)
- **Ceremonies:** `.squad/ceremonies.md` (Build Repair Check)
2 changes: 2 additions & 0 deletions .copilot/skills/release-process/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ confidence: "high"
source: "team-decision"
---

> ⚠️ **Squad CLI Only** — This skill documents the npm release runbook for Squad CLI (`@bradygaster/squad-sdk` and `@bradygaster/squad-cli`). It is NOT applicable to IssueTrackerApp (.NET/Blazor). For IssueTrackerApp releases, see `.squad/playbooks/release-issuetracker.md`.

## Context

This is the **definitive release runbook** for Squad. Born from the v0.8.22 release disaster (4-part semver mangled by npm, draft release never triggered publish, wrong NPM_TOKEN type, 6+ hours of broken `latest` dist-tag).
Expand Down
2 changes: 2 additions & 0 deletions .copilot/skills/squad-conventions/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ confidence: "high"
source: "manual"
---

> ⚠️ **Squad CLI Only** — This skill documents conventions for the [Squad CLI](https://github.com/bradygaster/squad) Node.js package. It is NOT applicable to IssueTrackerApp (.NET/Blazor). Agents working on IssueTrackerApp should ignore this skill.

## Context
These conventions apply to all work on the Squad CLI tool (`create-squad`). Squad is a zero-dependency Node.js package that adds AI agent teams to any project. Understanding these patterns is essential before modifying any Squad source code.

Expand Down
Loading
Loading