integration-test-writer · git:20261012.41aab41 · 2026-10-12 · sha256 eeea287ff50649be

integration-test-writer git:20261012.41aab41A

Immutable. This exact content never changes and is served at /api/v1/blob/eeea287ff50649be.

---
name: integration-test-writer
description: "Use when an endpoint or module needs integration tests in any project — requests through the real stack against a real test environment — when implement-feature dispatches a phase's tests, when the evaluator or qa-preflight dispatch the correction of a failing integration test or a missing query-growth test, or when a user asks to plan or write integration tests. Generic — the environment, the helpers, the data policy and the commands come from the test profile in the project's GATES.md, never from another project. Never modifies production code."
---

# Integration Test Writer

Plan and implement **integration tests** that validate real behavior against a real test
environment: the full request→response lifecycle, and what it changed. **Never modifies
production code** — if a test fails, only the test is adjusted.

> **The project defines the facts; this skill defines the discipline.** All hard rules (project
> profile, boundary, structure, data, authentication, assertions, query growth, the checklist,
> execution) are in **`references/integration-rules.md`** — read it before writing. Its first
> section tells you what to read from the project's `GATES.md`: suites, entry point,
> environment, authentication, data policy, query counter, and the path of the project's own
> rules, which are binding.
> **The suite's language has its own file,** `references/languages/<language>.md`: the same
> rules in that language's idiom, its anti-patterns, and a worked query-growth test. Read the
> one that applies, and only that one (`integration-rules.md`, "Language").
> Background on the SDD flow, not needed to run this skill: `https://github.com/dayvisonassis/sdd-skills/blob/main/docs/GUIA_DO_WORKFLOW.md`.

**Scope:** the integration suites the project profile names.

## INPUT

- `target_file_or_endpoint` (required) — a handler, a route, or an endpoint (`POST /orders`).
- `feature` (optional) — the feature folder's id (`F14`); decides where the checklist goes, and which endpoints the query-growth table covers. That folder's `spec.md` and `contract.md`, when it has them, are "the spec" the rules refer to.
- `mode` (optional) — `interactive` (default when a user calls) or `autonomous` (set by implement-feature/evaluator/qa-preflight).
- `language` (optional) — the suite's language (`javascript`, `python`, …). When given, it wins over what the profile and the repository say.
- `test_file_path` / `focus_areas` / `batch_size` (optional; default 8, from 5 to 10; a remainder smaller than 5 joins the last batch).
- `evaluation_report` (optional) — its `kind: test` entry selects the mode: an existing `testFile` → **correction mode**; none → write only what its `message` names (a missing query-growth test, or coverage for one rule).

## OUTPUT

- New or expanded integration tests where the profile says the suite's tests live.
- The checklist `integration-rules.md` describes ("The checklist"), with its query-growth table when the profile declares a query counter.
- Per-batch execution result, in the checklist's Execution part: how many tests ran, and the red run that proved the batch can fail.
- **One signal to the caller**, always one of: **"done — <test file paths>; checklist <path>"**, with paths relative to the repository root, followed by one line for each thing only the caller can act on, for what this run was asked to test (the whole target in a writing run, the flagged test or the named rule when an `evaluation_report` narrows it; what an earlier run recorded stays in the checklist and is not repeated) — **"red growth test: <title> — <the statement that repeats>"** for every growth test left red on the feature's own code, and **"spec mismatch: <behavior> — spec: <x>; code: <y>"** for every test written as the code behaves against the spec (rule F1); **"not resolved — environment: <which>"** (the integration harness is not declared and the repository does not reveal it, or the test environment cannot be reached). A "not resolved" run writes nothing.
- Production code untouched; the environment the same as before the run; nothing committed — the caller decides when the tests are committed.

---

## Invocation Modes

**Interactive (default):** full 3-phase process, **stop at the Phase 2 checkpoint** for explicit approval.

**Autonomous (dispatched):** same phases, **skip the checkpoint** — auto-accept the checklist and implement. Never pause.

**Correction mode (evaluator, `kind: test`, existing `testFile`):** fix **only** the flagged test
so it conforms to `integration-rules.md` and passes. Leave unrelated tests and production code
alone. When the report names a **missing query-growth test** (an endpoint, no failing test),
write that one test, or record the outcome that applies, in the checklist; touch nothing else.

---

## EXECUTION STEPS (3 Phases)

### Phase 1 — Analysis & Planning
1. Read the test-profile section of `GATES.md` and pick the suite: the integration suite whose sources contain the target's handler. Resolve its **language** (`integration-rules.md`, "Language") and read its file in `references/languages/`. A language with no file → the generic rules alone, noted in the checklist.
2. Build the **project profile** (`integration-rules.md`, first section). A required item missing from both `GATES.md` and the repository → return **"not resolved — environment: integration harness not declared (<items>)"**, naming every missing item.
3. Confirm the environment can be reached with the profile's commands: run an existing test of the suite, or, when it has none yet, open and close the environment through the profile's helpers. It cannot → **"not resolved — environment: <which>"**.
4. Read the project's rules file when the profile names one. It is binding.
5. Read existing tests of the suite for helpers and to avoid duplicating a case already covered.
6. Read the target fully — route, middleware, handler, data access — and map its code paths. With a `feature`, read its folder's `spec.md` and `contract.md` for what the endpoint is meant to do.
7. For every record a test will create: how it is created, what it depends on, and how it is removed, in the profile's removal order (D1–D8).
8. Map the scenarios (V2), each with an expected value that does not come from the product's own code (V5). When the profile declares a query counter, decide **one outcome per endpoint** in the scope of "Query growth — Scope and outcomes".

### Phase 2 — Checklist Creation
One row per test, plus the query-growth table, as `integration-rules.md` describes.
- **Interactive:** ask — is every failure path covered, including authentication and authorization? does any test create data it cannot remove? → **WAIT for approval.**
- **Autonomous / correction:** skip the checkpoint; proceed.

### Phase 3 — Batch Implementation
GROUP 5 to 10 tests per batch → IMPLEMENT per `integration-rules.md`, the language file and the
project's rules, with guaranteed cleanup in the profile's removal order → RUN the batch's
selection with the profile's command and read the result and **how many tests ran** → PROVE the
batch can fail (rule E5): invert every test's expectation, run once and see each one red at its
assertion with its cleanup done, restore, run once more → UPDATE the checklist → REPEAT. Run the
whole suite once at the end.

### Phase C — Correction mode
1. Build the profile and resolve the language as in Phase 1 (steps 1 to 4): a corrector needs the environment as much as a writer does. Read the report's entry (`testFile`, `targetFile`, `location`, `message`, `evidence`), the target, and the checklist that covers the test file, when there is one; with a `feature`, its `spec.md` and `contract.md` — a corrected expectation needs a source that is not the product's code (V5).
2. Run the narrowest selection that holds the flagged test, as the profile's commands and the language file define a selection — a name filter where they select by name, the file or the package otherwise — and read why it fails.
3. Fix the smallest footprint that makes it conform and pass, and run that selection again. The whole suite is not run.
4. When the test's assertion changed, prove that it can fail (rule E5) with the corrected test as a batch of one: invert it, run and see it red at its assertion with its cleanup done, restore, run once more.
5. Record the correction in the checklist that covers the test file, when there is one — the test's row, and one Execution line with the runs; the earlier lines stay as they are. Create none for a file that has none: the runs then go in the result. Return *done* — with a `red growth test` or a `spec mismatch` line only when it is about the flagged test.

---

## RULES

**Always:**
- Build the project profile from `GATES.md` before anything else, and follow `references/integration-rules.md` and the suite's language file exactly.
- Follow the project's own rules file where the profile names one; it wins where it is stricter.
- Open and close the environment through the profile's helpers.
- Create the test's own records and remove them in a block that runs even when the test fails, children before parents, by stored id, with no removal failing silently.
- Assert the status of every request, verify a write by reading it back, and write every expected value from outside the product's own code.
- Run every batch, count what ran, and see it red once.
- Record exactly one query-growth outcome per endpoint in scope, when the profile declares a counter.
- End with exactly one of the two signals in OUTPUT, with its `red growth test` and `spec mismatch` lines when it has any.

**Never:**
- Modify production code. Fix only tests.
- Change or remove data the test did not create, or leave data behind.
- Rely on a suite-level hook alone to remove what a test created.
- Replace the handler, the router or the data-access layer under test.
- Take a helper, a removal order or a command from another project or from memory instead of the project profile.
- Relax a query-growth assertion with a margin or a budget.
- Commit. The caller decides when the tests are committed.
- Pause for approval in autonomous or correction mode.

---

## Edge Cases

- **`GATES.md` has no test profile, but the suite exists:** build the profile from its config and helpers (the fallback column), say so in the checklist, and proceed.
- **`GATES.md` is absent, and the language file says the toolchain fixes the convention:** where tests live, how they are named and the two commands are the toolchain's. The entry point and the environment are never a convention: the repository shows them, or the harness is not declared.
- **Neither reveals a required item:** "not resolved — environment: integration harness not declared (<items>)". Declaring it is the `gate-builder`'s job.
- **The environment cannot be reached** (database down, container not started, wrong configuration): "not resolved — environment: <which>". Never point the suite at a non-test environment to get a run.
- **The whole-suite command fails for a reason that is not a test** (a path the runner does not accept, a script that does not exist): the tests proved by the selection's command stand. Return *done*, and report the command and its error in the result — repairing a gate's command is the `gate-builder`'s, not this skill's.
- **The profile says the suite's isolation replaces cleanup** (a rollback per test, a database per worker): rule D7 — do not add manual cleanup on top. A private database whose data policy still names removal helpers is not that case.
- **A record no helper can remove:** do not create it. Cover the behavior on existing data read-only, and record the gap in the checklist.
- **The suite's language has no file in `references/languages/`:** the generic rules alone, read in the language's own idiom; note it in the checklist. Never stop for it.
- **There is no spec** (no `feature`, or its folder has none): expected values come from what the test sent and created and from the rules the code states, the tests pin what the code decides, and the checklist says so once.
- **A test only passes by asserting behavior the spec contradicts:** write it as the code behaves, record the mismatch in the checklist (rule F1), and repeat it in a `spec mismatch` line of the signal — whoever dispatched the writer may be able to fix the code, and no dispatcher reads the checklist for it.
- **Dispatched again after the caller corrected the code** — it answered a `spec mismatch` line: the test that pinned the old behavior is now red; rewrite it to the spec and remove its note.
- **The profile declares no query counter:** no query-growth test and no outcome; say so once in the checklist.
- **A growth test is red on legacy code:** the `pre-existing N+1` outcome, with the statement and both locations; the red test is not committed.
- **A growth test is red on the feature's own code:** it stays red and unrelaxed, its title is the endpoint's outcome, and the signal names it with the statement that repeats. Never fix the production code, and never weaken the assertion to get a green run.
- **Called autonomously and the checklist reveals an ambiguity:** apply a best-practice default, note it in the checklist, and proceed.