Skip to content
Development
Command

/test-gate

Deterministic deploy-gate — verify a staging→main bundle's acceptance criteria against running code before deploy

BOOST
From plugin
forgedock
11980 skills80 commands
Install
> /plugin marketplace add RapierCraftStudios/ForgeDock
> /plugin install forgedock@forgedock

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/test-gate

Context preview

What this command does when you run it.

Deterministic deploy-gate — verify a staging→main bundle's acceptance criteria against running code before deploy

Command definition

test-gate.md
description: Deterministic deploy-gate — verify a staging→main bundle's acceptance criteria against running code before deploy
argument-hint: "[--prs \"<N1 N2 ...>\"] [--base <branch>]"
allowed-tools: Task, Bash, Read, Grep, Glob
install: extras

<!-- SPDX-FileCopyrightText: Copyright (c) RapierCraft Studios --> <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->

/test-gate — Deterministic Deploy-Gate Testing

> **Skill names**: `{FORGE_SKILL_PREFIX}` is `forgedock:` (plugin install) or empty (`install.sh`), resolved once per run by `commands/work-on.md` § Skill Name Resolution. If the skill is not found under either name, STOP and report "skill not found" — never run the phase inline.

**Input**: `$ARGUMENTS` — optional `--prs "<space-separated PR numbers>"` and `--base <branch>`.

Verifies a staging→main bundle's acceptance criteria against running code before deploy. Called by `/review-pr-staging` (Phase 6.5) with the bundle PRs, or run standalone when `--prs` is absent (computes the bundle itself). Returns a machine-readable BLOCK / PASS / SKIP verdict for the caller to consume.

**Agent model policy**: `model: "{DEFAULT_MODEL}"` — resolved from forge.yaml `agents.default_model`, else "sonnet" (standard tier). Fallback: `model: "opus"` if rate-limited. Feature gate: pass `effort` in Task/Skill spawns only on Claude Code >= 2.1.154. **NEVER use plan mode (EnterPlanMode).** **NEVER use the Agent tool** — test-gate dispatches test clusters via `Task` only. The Agent tool bypasses the allowed-tools constraint and produces output that cannot be structured into the machine-readable BLOCK / PASS / SKIP verdict.

<!-- FORGE:SPEC_LOADED — test-gate.md loaded and active. Agent is bound by this spec. -->

Forbidden Tools Self-Check

**Before executing any phase**, verify you are NOT using any of these tools:

| Tool | Status | Reason | |------|--------|--------| | `Agent` | **FORBIDDEN** | Bypasses allowed-tools constraint; produces unstructured output that cannot be parsed into the machine-readable BLOCK / PASS / SKIP verdict | | `EnterPlanMode` | **FORBIDDEN** | Breaks execution context; gate phases must execute, not be planned |

If you find yourself about to call `Agent(...)`, stop and use `Task(...)` instead.

**Posture**: Blocking-with-override at the staging→main boundary (mirrors the Phase 0A open-finding gate in `/review-pr-staging`). Posture is config-driven via `verification.test_gate`.

---

Config Resolution

Read `forge.yaml` **before** running any commands. All variable references below are populated from this block.

CONFIG_FILE="${FORGE_CONFIG:-forge.yaml}"
GH_REPO=$(yq '.project.owner + "/" + .project.repo' "$CONFIG_FILE")
GH_FLAG="-R $GH_REPO"
REPO_PATH=$(yq '.paths.root' "$CONFIG_FILE")
DEFAULT_BRANCH=$(yq '.branches.default' "$CONFIG_FILE")
STAGING_BRANCH=$(yq '.branches.staging' "$CONFIG_FILE")

# Test-gate config (all fields optional — defaults shown)
INTEGRATION_TESTS=$(yq '.verification.integration_tests // []' "$CONFIG_FILE")
TEST_SERVICES=$(yq '.verification.test_services // {}' "$CONFIG_FILE")
GATE_POSTURE=$(yq '.verification.test_gate.posture // "blocking"' "$CONFIG_FILE")
OVERRIDE_PHRASE=$(yq '.verification.test_gate.override_phrase // "OVERRIDE: shipping with test failures —"' "$CONFIG_FILE")

---

Input Parsing

BUNDLE_PRS=""
BASE_BRANCH="${DEFAULT_BRANCH}"

# Parse --prs and --base from $ARGUMENTS
while [[ "$@" ]]; do
  case "${1}" in
    --prs)   shift; BUNDLE_PRS="${1}";;
    --base)  shift; BASE_BRANCH="${1}";;
  esac
  shift
done

If `--prs` is absent, Phase 0 computes the bundle.

---

Missing-Config Guard (MANDATORY — runs before all phases)

# If integration_tests is empty/absent, exit ADVISORY — never crash
TEST_COUNT=$(yq '.verification.integration_tests | length' "$CONFIG_FILE" 2>/dev/null || echo 0)
if [ "${TEST_COUNT:-0}" -eq 0 ]; then
  echo "ADVISORY: verification.integration_tests is not configured in $CONFIG_FILE."
  echo "No tests to run. Emitting SKIP verdict."
  echo ""
  echo "To enable /test-gate, add to forge.yaml:"
  echo "  verification:"
  echo "    integration_tests:"
  echo "      - cluster: \"api\""
  echo "        command: \"pytest tests/integration/ -q --tb=short\""
  echo "        working_dir: \".\""
  echo "    test_services:"
  echo "      api: \"your-api-container-name\""
  echo "    test_gate:"
  echo "      posture: \"blocking\""
  echo "      override_phrase: \"OVERRIDE: shipping with test failures —\""
  # Emit structured SKIP verdict and exit
  echo "<!-- FORGE:TEST_GATE:SKIP|reason=no-tests-configured -->"
  echo "<!-- FORGE:TEST_GATE:RESULT=SKIP -->"
  exit 0
fi

---

Phase 0: Triage — Test-or-Skip

**Purpose**: Decide test-or-skip before any provisioning. Three ordered checks: 1. **0A** — no PRs in bundle → SKIP 2. **0B** — no executable file changes → SKIP (docs/config/markdown-only) 3. **0C** — no runtime-testable acceptance criteria → SKIP (all-manual or no criteria)

Every SKIP emits both a machine-readable verdict (`FORGE:TEST_GATE:RESULT=SKIP`) and a logged reason annotation (`FORGE:TEST_GATE:SKIP|reason=...`) so the caller and pipeline-health see a deliberate skip, not a silent gap.

0A: Resolve bundle PRs

git fetch origin ${DEFAULT_BRANCH} ${STAGING_BRANCH} 2>/dev/null

if [ -n "$BUNDLE_PRS" ]; then
  # Caller passed PR numbers explicitly (standard case when invoked by review-pr-staging)
  echo "Bundle PRs (from --prs): $BUNDLE_PRS"
else
  # Standalone invocation: compute bundle from staging→main diff
  BUNDLE_PRS=$(git log origin/${DEFAULT_BRANCH}..origin/${STAGING_BRANCH} --merges --oneline \
    | grep -oP '(?<=pull request #)\d+' \
    | sort -u \
    | tr '\n' ' ')
  echo "Bundle PRs (computed from ${STAGING_BRANCH}→${DEFAULT_BRANCH}): $BUNDLE_PRS"
fi

if [ -z "$BUNDLE_PRS" ]; then
  echo "No PRs found in bundle. Emitting SKIP verdict."
  echo "<!-- FORGE:TEST_GATE:SKIP|reason=no-bundle-prs -->"
  echo "<!-- FORGE:TEST_GATE:RESULT=SKIP
Read more
Ships withforgedock

ForgeDock — autonomous AI dev pipeline for Claude Code. GitHub as agent memory: issue in, PR out.

Get the whole plugin

Other commands on forgedock.