$npx -y skills add lucasfcosta/backpressured --skill manual-testingVerifies a feature works by running the real app, not by trusting green tests. Use when a backpressured loop reaches the before-done gate (Phase 3) and needs to confirm new behavior end-to-end — curling live API endpoints and driving a real browser via Playwright — including the
| 1 | # Manual Testing |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | **You are the machine that uses the feature the way a client or a person will, so a human isn't the first to find out it doesn't actually work.** Automated green is necessary, not sufficient: tests exercise the code, not the *running system*. Wiring, integration, env, and the error paths break in ways a passing unit test never sees. This is the "run it for real" gate. |
| 6 | |
| 7 | **Core principle: you only pass this on what you personally observed in the running app.** Not "tests pass, so it works." Not "I curled the happy path." You booted it, you drove it, you saw each acceptance criterion — and the cheap failure cases — behave. Evidence, not inference. |
| 8 | |
| 9 | ## When to Use |
| 10 | |
| 11 | - A `backpressured` loop's **Phase 3**, after automated checks are green, before the task is done. **Always run it here** — once before done, every time, even when the suite (including integration and end-to-end tests) is green. Automated tests are never a substitute (see [Boundaries](#boundaries)). The *only* thing that removes this gate is an explicit manual-testing opt-out in `BACKPRESSURE.md`'s **Skip** section. It's slower than tests, so don't run it every iteration — mid-loop, run it only when something warrants it; but the before-done gate is not optional. |
| 12 | |
| 13 | **Not for:** replacing automated tests or per-iteration checks (this is the end gate, not every patch). Gate by what exists: an API → curl it; a UI → drive the browser; genuinely nothing runnable (or an explicit `BACKPRESSURE.md` opt-out) → skip with a note saying why. A green test suite is **not** a reason to skip. |
| 14 | |
| 15 | ## Step 1 — Get the app running, for real |
| 16 | |
| 17 | Discover how to run it yourself — `package.json` scripts, `Makefile`, `docker-compose`, README, `.env.example` (or use project-specific run skills if they exist). Then actually boot it: start it in the background, tail the logs until it's genuinely healthy ("listening on :PORT", no startup errors), and note the URLs. |
| 18 | |
| 19 | Set up the **minimum real dependencies** to exercise the feature: bring up the DB, run migrations, seed at least one real row, and obtain a valid **auth token** and a real **id** if the feature needs them. If it genuinely can't boot (missing secret, broken dep), **report BLOCKED — do not fake it or skip to "tests pass."** |
| 20 | |
| 21 | ## Step 2 — Walk each acceptance criterion through the running system |
| 22 | |
| 23 | Exercise every acceptance criterion against the live app, not the test suite. |
| 24 | |
| 25 | - **API:** `curl -i` (status line visible) each endpoint. Check the **body shape, headers, and content** the consumer depends on — not just a 2xx. (CSV is actually CSV with the right `Content-Type`, not an empty body or a stack trace.) |
| 26 | - **UI:** drive a **real browser via the Playwright MCP** — navigate, fill, click the actual flow. Don't substitute a curl for a user action. |
| 27 | - **Transient states flicker.** A state like "button disabled while submitting" is too fast to catch by default — **throttle the network** (or observe the disabled attribute toggling) so you actually see it, rather than assuming it. |
| 28 | |
| 29 | ## Step 3 — Hit the cheap unhappy paths |
| 30 | |
| 31 | The failure cases are where manual testing earns its keep over automated tests — and they're trivial by hand. Exercise the ones in the acceptance criteria and the obvious ones around them: error responses (400 / 401 / 403 / 404), empty or invalid input, missing fields, the permission-denied case. Confirm the app returns the **status and the user-facing behavior** the feature promises (the inline error renders; the toast shows), not a 500 or a silent no-op. |
| 32 | |
| 33 | ## Step 4 — The UI: confirm function always, judge appearance only without a reference |
| 34 | |
| 35 | Two different things — don't conflate them: |
| 36 | |
| 37 | - **Functional state — always yours, reference or not.** Confirm the states the criteria promise actually happen: the submit button's `disabled` toggles, the inline error text renders, the toast appears. Capture screenshots / DOM observations of these as **evidence** regardless of whether a design reference exists — this is functional verification, not styling. |
| 38 | - **Appearance — conditional.** *No design reference provided* → take **sanity screenshots** and look for **obvious breakage** (blank page, broken layout, missing element). Judge only that it isn't visibly broken; something that merely looks off (placement, wording) is a **finding**, not a failure. *A Figma/Linear reference exists* → styling fidelity is **not your job** — defer it to [[visual-review]]; you still confirm the feature *functions* (the bullet above). |
| 39 | |
| 40 | ## Step 5 — Record the evidence, then judge |
| 41 | |
| 42 | "Tested manually, works" is not a passing check. Record the **actual |