Skip to main content

Chapter 2: The new delivery loop

The classic loop was write code, run it, fix it, repeat. Testing came after, when there was time. With an assistant, writing is the cheap step and the loop reorganises around the expensive ones.

Five steps​

StepQuestion it answersWho owns itTypical artefact
1. IntentWhat outcome do we want, for whom, and what are we not doing?YouA paragraph, a ticket, a sentence in a design doc
2. SpecificationWhat does "done" look like, precisely enough to be checked?You, with the assistant draftingAcceptance criteria, examples, interface signatures, failing tests
3. GenerationWhat code satisfies the specification?The assistant, with you steeringA diff
4. VerificationDoes the diff actually satisfy the specification, and nothing else?You, with toolsGreen tests, review notes, a security pass, a manual run
5. ReleaseHow does it reach users safely, and how will we know if it is wrong?YouMerge, deploy, feature flag, monitoring

The arrows matter as much as the boxes. Verification that fails sends you back to the specification, not to generation: if the assistant produced the wrong thing, the first suspect is that you described the wrong thing.

Step 1: Intent​

Intent is the part the assistant cannot supply. It is short, it is in plain language, and it names what is out of scope. A good intent statement fits in three sentences:

Users who paste a long transcript into the summariser get a timeout. We want summaries to return within 10 seconds for inputs up to 50,000 characters. We are not changing the summary format or the model.

Weak intent ("improve the summariser") produces weak everything downstream, because every gap is filled by a guess.

Step 2: Specification​

Module 2 is entirely about this step, so here is only the principle: a specification is a description of done that something other than the author can check. Acceptance criteria, input/output examples, interface signatures, and above all failing tests are specifications. "Make it work" is not.

The assistant is an excellent drafter of specifications. Ask it to propose acceptance criteria from your intent and you will get a list that is 70 % right and reveals, by what it gets wrong, exactly where your intent was ambiguous. That is the point of the exercise.

Step 3: Generation​

This is the step everyone focuses on and the step that matters least. Some rules that hold across tools:

  • Small steps. One function, one endpoint, one migration at a time. Large requests produce large diffs, and large diffs are where fabrication and scope drift hide.
  • Point at the spec. "Make the failing tests in tests/test_summariser.py pass without modifying them" is a better prompt than any amount of prose.
  • Name the constraints. Language version, allowed dependencies, existing helpers to reuse, conventions to follow. If it is not in the context, it does not exist for the model.
  • Stop early. If the first draft is going in the wrong direction, do not ask for fixes; restate the request. Patching a wrong approach produces a worse result than restarting.

Step 4: Verification​

Verification is now the engineer's main job. It has layers, from cheapest to most expensive:

  1. Does it compile / type-check / lint? Catches fabricated APIs and obvious shape errors. Free. Run it every time.
  2. Do the tests pass - including the ones that failed before? Catches "I made the tests pass by deleting the tests". Diff the test files separately and read them first.
  3. Does the diff match the request? Count files. Count lines. Anything outside the stated scope is rejected or split into its own change.
  4. Does it fit the codebase? Reuses existing helpers, follows error-handling and logging conventions, goes through the same middleware as everything else. This is where a second pass with the assistant helps: "list every place in this repository that does something similar to this new function".
  5. Is it safe? Secrets, injection, auth bypass, unsafe deserialisation, licence of any new dependency. Module 5 gives the checklist.
  6. Does it work for a human? Run it. Click it. Read the output. Models are very good at producing code that passes the tests it wrote and fails the user.

The order is deliberate: each layer is cheaper than the next, so failures should be caught as early as possible.

Step 5: Release​

Nothing about release is specific to AI, except the volume. When a team ships three times as many changes, it needs three times as much confidence per change or three times better rollback. Feature flags, canary deployments, and monitoring that would have told you about the problem before the customer did are no longer nice-to-have.

The loop in practice: a worked example​

Intent. Add an endpoint GET /api/orders/{id}/invoice that returns a PDF for an order the current user owns. Out of scope: generating invoices for other users, caching.

Specification (drafted with the assistant, edited by you):

  • Returns 200 with Content-Type: application/pdf when the order exists and belongs to the user.
  • Returns 404 when the order does not exist or belongs to someone else (do not leak existence).
  • Returns 401 when unauthenticated.
  • Reuses InvoiceRenderer from billing/render.py; no new PDF library.
  • Three tests written first, all failing.

Generation. One prompt: "Implement the endpoint so that the three failing tests in tests/api/test_invoice.py pass. Reuse InvoiceRenderer. Do not modify the tests."

Verification. Type-check: pass. Tests: pass, test file unchanged. Diff: one new route, one import, 31 lines - matches. Fit: route is registered through the same router as the other order endpoints, so auth middleware applies. Safety: the ownership check is in the query, not after it. Manual: opened the PDF in a browser.

Release. Merged behind the existing invoices_v2 flag, enabled for staff first.

Total time: under an hour. Most of it in steps 2 and 4. That ratio is the point.

Summary​

  • The loop is intent, specification, generation, verification, release. You own four of the five steps.
  • A failed verification sends you back to the specification, not the prompt.
  • Verification has layers; run the cheap ones every time and the expensive ones before merge.