The generate, run, correct loop

Small increments, real execution, real error output pasted back, and verification in the running application rather than in a summary.

The loop

The single biggest determinant of output quality is whether the code was actually run. A session that generates, runs, reads the failure and corrects, in a tight cycle, converges. A session that generates a large batch and asks 'does this look right?' produces plausible code that has never executed.

  1. Ask for one small increment - a function, a route, one component.
  2. Run it yourself, or ask the agent to run it, and read the output.
  3. Paste the actual failure back verbatim, not your interpretation of it.
  4. Let it correct, then run again.
  5. Verify in the interface. A passing unit test is not the same as a working feature.
# the agent should run this, and you should read the result
npm test -- cart.test.ts
npm run typecheck
npm run dev          # then actually click through the flow

# when a command is noisy, cap what enters the context
npm test 2>&1 | tail -40
⚠️
Never accept a summary in place of a run. 'I have implemented the fix and the tests should now pass' is not evidence, and it is the sentence most likely to precede a broken commit. Requiring the raw output costs nothing and removes an entire class of failure.

Sizing the increment

Increment sizeReviewable?Typical outcome
One functionEasyCorrect or obviously wrong
One route plus its testEasyUsually lands
One feature across three filesHard but doableNeeds review before merge
Five features in one promptNoHalf-works; hard to bisect
Full app from a paragraphImpossibleDemo quality, unmaintainable
  • Aim for a change you can read end to end in two minutes.
  • Commit after each successful increment, so a bad one is a revert rather than an archaeology exercise.
  • When the agent starts editing files you did not expect, stop and re-scope the request.
  • Run the app after UI work even when tests pass - layout and state bugs rarely appear in unit tests.
git add -p && git commit -m "cart: reject quantity above stock"

# next increment, as its own commit
# "now make the error message name the item that is short"

Verifying in the real interface

Do not stop at "the tests pass".

Check, in the running app:
- Empty state: what renders with no data
- Loading: is there a spinner or a flash of wrong content
- Error: does a failed request show something a user can act on
- Boundary: zero, one, many; very long strings
- Refresh: does the state survive, or reset confusingly
  • Tests are written by the same agent that wrote the code, so they encode the same misunderstanding. Manual verification is the independent check.
  • Click the path a user would click, not the path you know works.
  • If a screenshot tool is available, ask the agent to capture the rendered page - a visual diff catches what assertions miss.
  • Record what you checked. 'Verified empty, error and refresh states' is a review artefact.
// a cheap end-to-end sanity check the agent can run
import { test, expect } from "@playwright/test";

test("cart shows an actionable error when stock is short", async ({ page }) => {
  await page.goto("/product/limited");
  await page.getByRole("button", { name: "Add to cart" }).click();
  await page.getByRole("button", { name: "Add to cart" }).click();
  await expect(page.getByRole("alert")).toContainText("only 1 left");
});

FAQ

The agent says it ran the tests and they pass. Is that enough?
Only if you can see the output. Ask for the command and the raw result, and check the test actually exercises the new code - an agent can accidentally run a stale or unrelated suite. Verification you did not observe is not verification.
Why run the app when the tests are green?
Tests check the assertions someone thought to write. They do not check that the page renders, that the button is reachable, or that the empty state is not a blank screen. The running application is the only complete specification you have.

Prompting for intent, not syntax Specs and tests as the contract

Last refreshed 2026-09-18.