---
name: smoke-test
description: >
  Runtime smoke-test for a freshly-generated SmartStack.app project. Starts
  the backend (`dotnet run`) and the frontend (`npm run dev`) in the
  background, waits for both to become reachable, then probes every page
  route and every API endpoint scaffolded by the pipeline. Fails the run
  if ANY endpoint returns a 4xx/5xx status code or if any page is missing
  from disk. Designed to be the final gate of `ba-develop`
  so cross-stack drift surfaces in CI rather than at the user's first
  manual `npm run dev`.
group: development
cli: run-smoke
mode: execute
allowed-tools: [Read, Glob, Grep, Bash]  # Bash: CLI invocation
---

# smoke-test — Runtime gate for freshly-scaffolded projects

## Why this skill exists

`/ba-develop` currently builds (`dotnet build` + `npm run
type-check`) and runs unit tests, but **never starts the application**.
Static audits (`audit-dev-frontend`, `audit-pre-dev`) grep the generated
sources for patterns ; they cannot tell you whether the running app
serves the routes the frontend believes exist.

The ba-002 (Budgets, 2026-05-10) regression exhibited four runtime
failures that every existing gate missed :

- `404 GET /api/budgets/dashboard/alerts` — frontend hook emitted, backend
  endpoint not scaffolded (cross-stack drift)
- `404 GET /api/budgets/dashboard/consolidated` — same drift
- `405 POST /api/budgets/dashboard/budgets/{id}/export` — wrong verb on
  the controller side
- `400 GET /api/user/preferences/for-tenant/{guid}` — platform endpoint
  contract drift, hidden by the absence of a runtime probe

A single end-to-end smoke probe catches all four classes.

## What this skill does

It is invoked as the **last step** of `ba-develop`, after all
scaffolders + audits have completed and before the orchestrator emits
its « done » signal :

1. Spawns the backend (`dotnet run --project <api-csproj>`) in the
   background, waits for `GET /health` (or `/swagger/index.html` as
   fallback) to return 200.
2. Spawns the frontend (`npm run dev` — Vite) in the background, waits
   for `GET /` to return 200 on the configured port (default `3000`).
3. **Page probe** : for each `pageSpec.filePath` in the PRD slice,
   derives the expected URL (`/{appCode}/{module}/{section}/...`) and
   issues a `GET`. Fail if status ≠ 200.
4. **API probe** : extracts every URL referenced inside the generated
   `src/services/api/*.ts` and `src/hooks/use*.ts` files (the canonical
   set of endpoints the frontend will hit). Issues a `GET` (with
   sensible header defaults) and fails on any 4xx/5xx.
5. Tears down both processes ; emits the standard `executeEnvelope`
   with a structured `report` summarising probed routes, statuses,
   and timings.

## How to invoke

```
npx tsx skills/development/smoke-test/cli/run-smoke/index.ts \
  --project-path <path-to-feature-folder> \
  --prd-slice <path-to-prd-slice.frontend.json> \
  [--backend-port 5000] [--frontend-port 3000] [--timeout-ms 60000]
```

The CLI exits with a non-zero status (and emits `success=false` in the
envelope) on the FIRST endpoint that fails its probe, after best-effort
teardown of the two background processes.

## What it does NOT do (v1 scope)

- **No browser test** (Playwright / headless Chromium) — the v1 probes
  HTTP only. The v2 milestone adds a browser navigation pass that
  captures `console.error` events.
- **No load test** — single GET per endpoint, no concurrency.
- **No auth flow** — uses anonymous probing ; endpoints requiring login
  are flagged as `skipped` in the report (not failed). v2 may inject
  a test JWT.
- **No data assertion** — only status codes are checked. The aim is to
  catch missing endpoints (404), wrong verbs (405) and broken contracts
  (400/500) — not to validate response shapes.

## Wiring as the final gate of ba-develop

The orchestrator MUST invoke this skill as its last step. If the smoke
test fails, the orchestrator **must not signal « done »** ; instead it
should surface the failing endpoints to the user and route to the
relevant fix-skill (controller for 404 on a missing backend endpoint,
frontend-component for a misnamed hook URL, etc.).

The skill's envelope `report.failures[]` carries enough metadata
(`endpoint`, `verb`, `status`, `expectedBy`) for a programmatic
dispatcher to fan out the corrections without re-asking Claude.
