Battle-test the current change
Decide what can be run, run it, score how well the change is actually covered, and hand back the
checks a human still has to do. $ARGUMENTS narrows the side (frontend/backend) and the git
scope; blank means both sides, all pending changes.
Phase 1 - Triage (before running anything)
- Resolve the scope:
staged -> git diff --cached, unstaged -> git diff, last-commit ->
git diff HEAD~1 (empty tree if there is no parent), blank -> both diffs. Add untracked files
(git ls-files --others --exclude-standard): a brand-new module is invisible to git diff and
is exactly the code least likely to be covered. Not a git repo (git rev-parse --git-dir fails)
-> fall back to the files the user names, and say the scope came from them, not from git.
- Empty-diff guard: no changes in scope -> say so and stop. Do not run a suite for nothing.
- Detect what the repo actually has (
package.json scripts, composer.json, Makefile,
pytest/cargo/go, a dev script, a compose file, an emulator), then sort every check that
matters for this diff into three buckets and print them before executing anything:
- AUTO - runnable now, non-destructive, no credentials: test/typecheck/lint/build scripts,
and single-file language checks (
php -l through the Docker wrapper, tsc --noEmit,
node --check).
- BOOTABLE - runnable after starting something the repo owns: dev server, Docker stack,
emulator. Start it, use it, stop only what this run started.
- MANUAL - impossible here: prod or client credentials, a real payment, a real device, a
third-party dashboard, an email or message actually arriving, a visual judgment call, or a
production DB change.
Bucket by what the diff touches, not by what the repo owns. A backend-only diff earns no browser
pass.
- Blast-radius preflight, before the first command runs. A check that can reach real data or a
real person is NOT auto, whatever the script is named. The default is refuse, not try:
- Read the env the command will actually use (
.env*, firebase.json / .firebaserc, the
compose file, the test config) before running it. Pointed at a production project, a live API
key, a shared staging DB, a real SMTP host or a third-party webhook -> MANUAL. Prefer the
repo's emulator or test env; if the only env available is the real one, do not run it.
- Anything that reaches a human (email, SMS, WhatsApp, push, a call to a partner API that
bills or writes) is MANUAL even in "test mode", unless the repo pins a sandbox you verified.
- Anything that mutates a store: seed, reset, migrate, truncate,
--force, fixtures that
drop collections. MANUAL unless it provably targets a local throwaway you started.
- Rate-limited or paid third parties (Apollo, LinkedIn, HubSpot, OpenAI, a payment provider):
MANUAL. Burning a client's quota to raise a score is not a trade worth making.
When you cannot tell which env a command uses, it is MANUAL. State the reason in one line and
move on; an unrun check costs points, and that is the correct outcome.
Phase 2 - Backend
Run AUTO first, then BOOTABLE. Keep the tail of a passing command, the full output of a failing one.
PHP goes through the Docker wrapper; if Docker is down, that check moves to MANUAL instead of being
skipped silently.
If the diff adds non-trivial logic that no suite covers, write ONE minimal runnable assertion for it
(the smallest thing that fails if the logic breaks), run it, and say you added it.
Phase 3 - Frontend (only when the diff touches UI)
Delegate to /frontend-verify; do not reimplement browser driving. Cover its two gaps first:
- Preflight:
playwright-cli --help. Missing -> the browser pass goes to MANUAL with the
install command, the run continues.
- Which backend the page will talk to, checked before booting anything. A dev server is a
browser pointed at whatever its env says. If that env is the live project (a real Firebase
project id with no emulator flag, a prod API base URL, real keys), the browser pass is MANUAL:
loading a route reads, writes and authenticates against real user data. Boot it only against the
repo's emulator or sandbox env, and only by setting the flag the repo already provides (for
example
VITE_USE_EMULATORS=true with firebase emulators:start), never by editing .env.
Cannot tell which backend it hits -> MANUAL.
- Dev server:
/frontend-verify never starts one. Probe the base URL; if nothing answers, start
the repo's dev script in the background and poll, never sleep-and-hope:
timeout 30 bash -c 'until curl -sf http://localhost:3000 >/dev/null; do sleep 1; done'.
Stop it by killing the port listener only: lsof -ti:3000 -sTCP:LISTEN | xargs kill. Never
pkill -f node|vite|next, it can kill this session. A server that was already up stays up.
Phase 4 - Score out of 100
Start at 0, add only what was observed:
| Signal |
Pts |
| The changed code path was executed at all, not merely compiled or linted |
30 |
| An automated assertion covers the specific new behaviour |
25 |
| Every error/edge branch the diff introduces was exercised |
15 |
| The existing suite ran in full and is green |
15 |
| The real surface was driven end to end (browser pass, or a real API call) |
10 |
| Nothing in MANUAL is load-bearing for the change to be correct |
5 |
Green-but-shallow scores low: a passing typecheck with the new function never called is <= 30. Never
round up to be encouraging.
Phase 5 - Report
Ran: 4 checks (3 green, 1 red)
OK pnpm typecheck, pnpm lint, vitest (28 passed)
RED pnpm test - cart.spec.ts:41 expects the old status value
Battle-tested: 45/100
The new webhook branch never ran; only the happy path is asserted.
Manual (2):
1. Pay with a real card in Stripe test mode, confirm the order flips to paid.
2. Apply the migration by hand before this ships.
Red is stated as red with its output, never softened. No MANUAL items -> Manual: none. A check
that was skipped goes to MANUAL: silence reads as "checked and fine", which is a lie. Mention the
disposable .frontend-verify/ directory if a browser pass wrote one.
Do NOT
The hard rule: this skill must never change real data or reach a real user. A check that can
only run against the real thing does not run. It goes to MANUAL, it costs points, and that is the
right answer. A lower score is always cheaper than a client's data.
- Never run anything that writes to a production database or a live client environment. No SQL
against a production DB over SSH, ever; DB changes go to MANUAL to be applied by hand. A
*deploy*.sh wrapper goes to MANUAL too, whatever it claims to test.
- Never point a check at prod to make it runnable. Do not edit
.env, swap a config, or export a
credential to get a suite to pass. Run it in the repo's sandbox or not at all.
- Never commit, push, or deploy. This skill reports.
- Never leave a process running that this run started.
- Never claim a check passed that was not executed.
- No new test framework, config file, CI wiring, or fixtures. Use what the repo already has.
1---2name: battle-test3description: Run the frontend and backend checks that CAN actually be run for the current change, then report what ran, a battle-tested score out of 100, and the checks that still need a human. Use after implementing a feature or a bugfix and before committing it: "test this", "run the tests", "did I break anything", "how solid is this change", "what still needs manual testing", "teste ça", "est-ce que c'est bien testé". Runs the repo's own tooling only, never a new framework. It reports; it never commits, pushes, or deploys.4---56# Battle-test the current change78Decide what can be run, run it, score how well the change is actually covered, and hand back the9checks a human still has to do. `$ARGUMENTS` narrows the side (`frontend`/`backend`) and the git10scope; blank means both sides, all pending changes.1112## Phase 1 - Triage (before running anything)13141. Resolve the scope: `staged` -> `git diff --cached`, `unstaged` -> `git diff`, `last-commit` ->15 `git diff HEAD~1` (empty tree if there is no parent), blank -> both diffs. **Add untracked files**16 (`git ls-files --others --exclude-standard`): a brand-new module is invisible to `git diff` and17 is exactly the code least likely to be covered. Not a git repo (`git rev-parse --git-dir` fails)18 -> fall back to the files the user names, and say the scope came from them, not from git.192. **Empty-diff guard**: no changes in scope -> say so and stop. Do not run a suite for nothing.203. Detect what the repo actually has (`package.json` scripts, `composer.json`, `Makefile`,21 `pytest`/`cargo`/`go`, a dev script, a compose file, an emulator), then sort every check that22 matters **for this diff** into three buckets and print them before executing anything:23 - **AUTO** - runnable now, non-destructive, no credentials: test/typecheck/lint/build scripts,24 and single-file language checks (`php -l` through the Docker wrapper, `tsc --noEmit`,25 `node --check`).26 - **BOOTABLE** - runnable after starting something the repo owns: dev server, Docker stack,27 emulator. Start it, use it, stop only what this run started.28 - **MANUAL** - impossible here: prod or client credentials, a real payment, a real device, a29 third-party dashboard, an email or message actually arriving, a visual judgment call, or a30 production DB change.3132Bucket by what the diff touches, not by what the repo owns. A backend-only diff earns no browser33pass.34354. **Blast-radius preflight, before the first command runs.** A check that can reach real data or a36 real person is NOT auto, whatever the script is named. The default is refuse, not try:37 - **Read the env the command will actually use** (`.env*`, `firebase.json` / `.firebaserc`, the38 compose file, the test config) before running it. Pointed at a production project, a live API39 key, a shared staging DB, a real SMTP host or a third-party webhook -> **MANUAL**. Prefer the40 repo's emulator or test env; if the only env available is the real one, do not run it.41 - **Anything that reaches a human** (email, SMS, WhatsApp, push, a call to a partner API that42 bills or writes) is MANUAL even in "test mode", unless the repo pins a sandbox you verified.43 - **Anything that mutates a store**: seed, reset, migrate, truncate, `--force`, fixtures that44 drop collections. MANUAL unless it provably targets a local throwaway you started.45 - **Rate-limited or paid third parties** (Apollo, LinkedIn, HubSpot, OpenAI, a payment provider):46 MANUAL. Burning a client's quota to raise a score is not a trade worth making.47 When you cannot tell which env a command uses, it is MANUAL. State the reason in one line and48 move on; an unrun check costs points, and that is the correct outcome.4950## Phase 2 - Backend5152Run AUTO first, then BOOTABLE. Keep the tail of a passing command, the full output of a failing one.53PHP goes through the Docker wrapper; if Docker is down, that check moves to MANUAL instead of being54skipped silently.5556If the diff adds non-trivial logic that no suite covers, write ONE minimal runnable assertion for it57(the smallest thing that fails if the logic breaks), run it, and say you added it.5859## Phase 3 - Frontend (only when the diff touches UI)6061Delegate to `/frontend-verify`; do not reimplement browser driving. Cover its two gaps first:6263- **Preflight**: `playwright-cli --help`. Missing -> the browser pass goes to MANUAL with the64 install command, the run continues.65- **Which backend the page will talk to, checked before booting anything.** A dev server is a66 browser pointed at whatever its env says. If that env is the live project (a real Firebase67 project id with no emulator flag, a prod API base URL, real keys), the browser pass is **MANUAL**:68 loading a route reads, writes and authenticates against real user data. Boot it only against the69 repo's emulator or sandbox env, and only by setting the flag the repo already provides (for70 example `VITE_USE_EMULATORS=true` with `firebase emulators:start`), never by editing `.env`.71 Cannot tell which backend it hits -> MANUAL.72- **Dev server**: `/frontend-verify` never starts one. Probe the base URL; if nothing answers, start73 the repo's dev script in the background and poll, never sleep-and-hope:74 `timeout 30 bash -c 'until curl -sf http://localhost:3000 >/dev/null; do sleep 1; done'`.75 Stop it by killing the port listener only: `lsof -ti:3000 -sTCP:LISTEN | xargs kill`. Never76 `pkill -f node|vite|next`, it can kill this session. A server that was already up stays up.7778## Phase 4 - Score out of 1007980Start at 0, add only what was observed:8182| Signal | Pts |83|---|---|84| The changed code path was executed at all, not merely compiled or linted | 30 |85| An automated assertion covers the specific new behaviour | 25 |86| Every error/edge branch the diff introduces was exercised | 15 |87| The existing suite ran in full and is green | 15 |88| The real surface was driven end to end (browser pass, or a real API call) | 10 |89| Nothing in MANUAL is load-bearing for the change to be correct | 5 |9091Green-but-shallow scores low: a passing typecheck with the new function never called is <= 30. Never92round up to be encouraging.9394## Phase 5 - Report9596```97Ran: 4 checks (3 green, 1 red)98 OK pnpm typecheck, pnpm lint, vitest (28 passed)99 RED pnpm test - cart.spec.ts:41 expects the old status value100Battle-tested: 45/100101 The new webhook branch never ran; only the happy path is asserted.102Manual (2):103 1. Pay with a real card in Stripe test mode, confirm the order flips to paid.104 2. Apply the migration by hand before this ships.105```106107Red is stated as red with its output, never softened. No MANUAL items -> `Manual: none`. A check108that was skipped goes to MANUAL: silence reads as "checked and fine", which is a lie. Mention the109disposable `.frontend-verify/` directory if a browser pass wrote one.110111## Do NOT112113**The hard rule: this skill must never change real data or reach a real user.** A check that can114only run against the real thing does not run. It goes to MANUAL, it costs points, and that is the115right answer. A lower score is always cheaper than a client's data.116117- Never run anything that writes to a production database or a live client environment. No SQL118 against a production DB over SSH, ever; DB changes go to MANUAL to be applied by hand. A119 `*deploy*.sh` wrapper goes to MANUAL too, whatever it claims to test.120- Never point a check at prod to make it runnable. Do not edit `.env`, swap a config, or export a121 credential to get a suite to pass. Run it in the repo's sandbox or not at all.122- Never commit, push, or deploy. This skill reports.123- Never leave a process running that this run started.124- Never claim a check passed that was not executed.125- No new test framework, config file, CI wiring, or fixtures. Use what the repo already has.