Skip to content
Open
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
56 changes: 47 additions & 9 deletions .claude/skills/pair-capability-publish-pr/SKILL.md

Large diffs are not rendered by default.

23 changes: 20 additions & 3 deletions .claude/skills/pair-capability-setup-gates/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
name: pair-capability-setup-gates
description: "Configures CI/CD quality gates — pipeline config, shared lint/format packages, husky hooks, the required deterministic secret-scanning job (gitleaks by default, R6.5/D24) — for the adopted tech stack. Invoke directly to set up or reconfigure gates; idempotent — confirms existing configuration rather than re-configuring."
version: 0.5.1
description: "Configures CI/CD quality gates — pipeline config, shared lint/format packages, husky hooks, the required deterministic secret-scanning job (gitleaks by default, R6.5/D24), and the required pair-review + pair-explicit-approval branch-protection checks that make the review unskippable — for the adopted tech stack. Invoke directly to set up or reconfigure gates; idempotent — confirms existing configuration rather than re-configuring."
version: 0.6.0
author: Foomakers
---

Expand Down Expand Up @@ -125,11 +125,26 @@ Configure CI/CD quality gates for the project. Reads quality assurance guideline
- **`TIERING = disabled` (default) → full-suite pipeline**: every PR runs base (install + lint + type + build) **and** unit **and** integration/E2E **and** coverage — all jobs unconditional, no tag resolution, no `risk:*` reads. This is the safe default; do **not** generate the tier-aware jobs.
- **`TIERING = enabled` (opt-in) → tier-aware pipeline** following [tier-aware-pipeline.md](../../../.pair/knowledge/guidelines/infrastructure/cicd-strategy/tier-aware-pipeline.md): the pipeline **reads the PR's `risk:*` tag only** (via [`tier-resolve.sh`](../../../.pair/knowledge/assets/tier-resolve.sh) — tags only, no classification criteria of its own, D18) and schedules the [quality-model.md](../../../.pair/knowledge/guidelines/quality-assurance/quality-model.md) §4 matrix: base every tier, unit from 🟡, integration/E2E from 🔴; **untagged/unknown/malformed ⇒ 🔴** (fail-safe); a required suite missing at a tier ⇒ **explicit failure** (`require_suite`), never a silent pass. Do not copy any tier threshold into the generated config — it is a projection of the model, not a second source.
- **Coverage job (opt-in)**: emit the `coverage` job from [tier-aware-pipeline.md](../../../.pair/knowledge/guidelines/infrastructure/cicd-strategy/tier-aware-pipeline.md#coverage-guardrail-opt-in-regression-gate-consumed-by-this-pipeline) **only when `COVERAGE_GUARDRAIL = enabled`** (Step 3.4). It sources [`coverage-gate.sh`](../../../.pair/knowledge/assets/coverage-gate.sh) (config + a number only, no criteria — D18), reads `tech/coverage-baseline.md`, and blocks a regression below the committed baseline (maintain/improve passes; bootstrap-only when unset). With the flag absent (default) do **not** emit a coverage job in either pipeline mode.
- **Wire required checks**: mark `base` and `secret-scan` as required status checks on the protected branch. In full-suite mode all suite jobs are required; in tier-aware mode the tier-scoped jobs are required-when-scheduled (or via one aggregating gate job). A red gate blocks merge either way. The coverage job (when enabled) is required-when-scheduled like the other tier-scoped jobs.
- **Wire required checks**: mark `base` and `secret-scan` as required status checks on the protected branch. In full-suite mode all suite jobs are required; in tier-aware mode the tier-scoped jobs are required-when-scheduled (or via one aggregating gate job). A red gate blocks merge either way. The coverage job (when enabled) is required-when-scheduled like the other tier-scoped jobs. The two **pair review** checks are wired in Step 4.5 — they are required in both pipeline modes and are not tier-scoped away.
- **Post-merge staging** (on merge to the main branch): **build + deploy only, no gate re-run** — the gate already passed pre-merge (identical in both modes).
3. **Act**: Write the secret-scanning job — required, not an optional proposal line, in **both** pipeline modes: resolve the scanner (Argument > Adoption's Custom Gate Registry override > KB default gitleaks), then write the [CI Job Template](../../../.pair/knowledge/guidelines/quality-assurance/security/secret-scanning.md#ci-job-template-github-actions) into the same pipeline file as a `required` job, and provision a starting `.gitleaks.toml` at the project root (see the [allowlist mechanism](../../../.pair/knowledge/guidelines/quality-assurance/security/secret-scanning.md#allowlist-mechanism-adoption-controlled)) if one doesn't already exist. Never write the job with `continue-on-error` — fail-closed is not optional (R6.5).
4. **Verify**: Configuration files written, including the pre-merge pipeline (full-suite by default; tag-only tier-aware resolution + tier-scoped jobs only when `TIERING = enabled`) + required-check wiring, the post-merge staging (build+deploy only) config, the secret-scanning job, and `.gitleaks.toml`. If tiering is enabled, grep the generated pipeline for classification tokens (schema/diff/path heuristics) — there must be none (D18). If disabled, confirm no `risk:*` resolution was generated and every suite job runs unconditionally.

### Step 4.5: Wire the Pair Review Required Checks + Branch Protection

The gate is only half the merge block. The judgment review must be **unskippable**, which means it is a required check like any mechanical one — see [pr-states.md](../../../.pair/knowledge/guidelines/collaboration/project-management-tool/pr-states.md) for the state model and the two check contracts. This step is **host-agnostic**: the concrete API calls live in the code host's implementation guide (R2.12), e.g. [github-implementation.md](../../../.pair/knowledge/guidelines/collaboration/project-management-tool/github-implementation.md) § "PR state flow — required checks & branch protection".

1. **Check**: Does the protected branch already require `pair-review` and `pair-explicit-approval`? Read the current branch-protection configuration from the code host.
2. **Skip**: If both contexts are already required (and stale-review dismissal is on) → confirm and move to Step 5. Idempotent: never re-apply an identical protection payload.
3. **Act — prerequisites first (ordering is load-bearing)**: before writing any protection, (a) **provision the `pr-state:*` labels** from the host guide (they never auto-create; absence is non-blocking but the view is lost), (b) **write the `pair-explicit-approval` job** into the repository's workflows on the **target branch** — neither needs admin scope — and (c) **observe both contexts reporting on a real PR, twice**: at PR open, and again after a review submission (the approval-time re-evaluation), each time **on the PR's head commit** — that is the only commit the host's protection reads. Requiring a context that has never reported leaves **every** PR permanently unmergeable, and a context that reports only at PR open leaves a 🔴 PR blocked *after* the human approves; so protection is applied last, with the host's admin-bypass setting (`enforce_admins` on GitHub) enabled only after one PR has merged through the new rule.
4. **Act — required checks**: add both contexts to the protected branch's required status checks, alongside the gate jobs from Step 4:
- **`pair-review`** — published by `/pair-process-review` on the head commit (pending at PR creation via `/pair-capability-publish-pr`). Required in **both** pipeline modes and at **every** tier: it is never tier-scoped away, exactly like `secret-scan`. A `pending`/absent check blocks the merge, so a review that never ran or crashed cannot yield a mergeable PR (R5.7).
- **`pair-explicit-approval`** — verifies a **non-author human** approval on the current head when the tier requires it (🔴, and untagged ⇒ 🔴 fail-safe); auto-passes at 🟢/🟡 (D10). Generate its job from the host guide's template **unmodified in three respects**, because all three are authorization properties rather than style: it must run from a **trusted ref** (the target branch's version of the job and of any projection it sources — never the pull request's own tree, or the change under review could rewrite the check that authorizes it); its verdict must be **pinned to the PR head commit** on every re-evaluation (including the approval-triggered one), since that is the commit protection evaluates; and it must publish a **pending result as its first step**, so a cancelled or aborted re-evaluation leaves a merge-blocking context instead of a stale `success` from a lower tier. When registering it, **pin the context's producer** where the host allows it (on GitHub: the `checks[].app_id` form, not the legacy `contexts` array) — an unpinned status context can be satisfied by any principal with push access, including the reviewing agent, which would void the 🔴 gate. `pair-review` stays unpinned by construction (no app publishes it): it is an anti-accident control, not an authorization one — see the host guide's "What each context proves". It reads the `risk:*` label only — no classification criteria (D18). **Single-maintainer repositories**: the host rejects a self-approval, so 🔴 PRs cannot satisfy this context without a second human account — say so explicitly and offer to leave the context out of the required list (🔴 rule advisory, recorded) rather than making every 🔴 PR unmergeable.
- Also state the **approval count** explicitly in the protection payload when the host has one (GitHub: `required_approving_review_count: 0`) — the tier-scoped job is the approval authority; an unstated default of ≥1 would demand a human approval on **every** PR, contradicting the 🟢 self-merge row of quality-model §4.
5. **Act — stale-approval invalidation**: enable the host's dismiss-stale-reviews equivalent so a force-push invalidates a previous human approval (pr-states.md edge case).
6. **Act — degraded mode**: if the host has **no required-check / branch-protection API**, or the token lacks permission, do **not** silently continue: report `Required checks: DEGRADED — enforcement advisory` and emit the host guide's **manual** setup steps (which contexts to require, where). Record the gap in [way-of-working.md](../../../.pair/adoption/tech/way-of-working.md)'s Quality Gates section so it is visible until applied.
7. **Verify**: Both contexts are required on the protected branch (or the degradation is reported with manual instructions), the labels exist (or their absence is reported as non-blocking), the `pair-explicit-approval` job is committed to the repository, and stale approvals are dismissed on force-push. Grep the generated `pair-explicit-approval` job for classification tokens — there must be none (D18).

### Step 5: Provision Shared Lint/Format Config + Hooks

1. **Check**: For each config already detected in Step 1 that is not conflicting, skip provisioning it and note it as already present.
Expand Down Expand Up @@ -167,6 +182,7 @@ GATE CONFIGURATION COMPLETE:
├── Pre-merge tiering: [disabled (default — full suite every PR) | enabled (risk-tier-scoped, opt-in)]
├── Coverage guardrail: [disabled (default — no coverage job) | enabled (opt-in — coverage job + tech/coverage-baseline.md created)]
├── Required checks: [base + secret-scan required; full-suite: all suite jobs required | tier-aware: tier-scoped jobs required-when-scheduled]
├── Pair review: [pair-review + pair-explicit-approval required on <branch> (stale approvals dismissed) | DEGRADED — enforcement advisory, manual setup steps emitted | already configured]
├── Secret Scan: [gitleaks (KB default) | <override> — job + .gitleaks.toml written | already configured]
├── Shared configs: [package list | N/A — non-JS, documented pointer only]
├── Hooks: [husky pre-commit + pre-push | override: <tool> | N/A]
Expand Down Expand Up @@ -200,6 +216,7 @@ See [graceful degradation](../../../.pair/knowledge/guidelines/technical-standar
- **Full checks are the default; risk-tier reduction is opt-in** (ADL 2026-07-20): unless the project sets `Pre-merge tiering: enabled` in way-of-working.md (Step 3.3 opt-in), the generated pipeline runs the **full suite on every PR** — the safe, pre-tiering behavior. Tiering only *reduces* checks on lower-risk PRs, so it must be enabled explicitly.
- **Coverage guardrail is opt-in, off by default** (story #282): the `coverage` regression job and `tech/coverage-baseline.md` are generated **only** when the project sets `Coverage guardrail: enabled` (Step 3.4 opt-in) — the twin of the tiering opt-in. Absent the flag, no coverage job and no baseline file. The baseline is human-committed; the gate bootstraps advisory-only (suggests on stderr, never persists — a CI checkout is ephemeral; automated commit-back is story #372). See [coverage-config-example.md](../../../.pair/knowledge/assets/coverage-config-example.md).
- **When tiering is enabled, the generated pipeline reads classification tags only, never classifies** (D18): tier criteria live in [quality-model.md](../../../.pair/knowledge/guidelines/quality-assurance/quality-model.md) §3/§4; the pipeline is the deterministic Automation layer that projects the matrix from the PR's `risk:*` tag. Untagged ⇒ 🔴 (fail-safe). See [tier-aware-pipeline.md](../../../.pair/knowledge/guidelines/infrastructure/cicd-strategy/tier-aware-pipeline.md).
- **The pair review is a required check, not a convention** (story #234): Step 4.5 wires `pair-review` + `pair-explicit-approval` on the protected branch so the judgment review is mechanically unskippable (R5.7) and 🔴 PRs need an explicit human approval (D10). The state model, the check contracts, and the degraded mode live in [pr-states.md](../../../.pair/knowledge/guidelines/collaboration/project-management-tool/pr-states.md); host API specifics live in the host's implementation guide (R2.12). This skill wires the checks — it never renders a verdict and never computes a PR state.
- **Secret scanning is CI config, not a judgment call** (D24, anti-complexity): this skill provisions the job mechanically; it never evaluates whether a diff contains a secret itself — that is gitleaks' (or the adopted scanner's) job at runtime, with no LLM in the loop. `/pair-capability-assess-security` never re-implements this — see that skill's own Notes.
- **Idempotent** — see [idempotency convention](../../../.pair/knowledge/guidelines/technical-standards/ai-development/skill-conventions/idempotency.md). This skill's check: an already-configured project (incl. provisioned shared configs and hooks) is confirmed; update only on explicit developer request. Conflicting local config is always resolved by asking first (see Edge Cases above).
- Gate commands must be executable in the project's development environment. Verify commands exist before writing.
Expand Down
Loading
Loading