AI-Assisted Engineering – Turning a Ticket into Requirements

September 12, 20265 min readUpdated 10/4/2026

Most tickets are one sentence long, and most bugs that reach production were decided in that sentence: in what it did not say, and in what someone quietly assumed instead. An AI assistant is very good at finding the gaps in a ticket. It is not entitled to fill them. This post is about using it for the first job without letting it do the second.

The ticket

This is the whole ticket the series' feature started from, as the product owner wrote it:

PIZZA-42: As a signed-in customer, I want to pay with one of my saved cards at
checkout so I don't have to type my card every time.

It reads as complete. It is not. Does the primary card come preselected? What happens to expired cards? If a saved card is declined, can the customer try another on the same order? Which of the app's four frontends does this cover? An assistant asked to "implement PIZZA-42" will answer every one of those questions, silently, by picking something reasonable. Each pick is a product decision made by nobody.

Ask for questions, not answers

The requirements session resumed the analysis conversation, so it already knew the code. The prompt forbade planning and asked for the opposite of a solution:

Using what you found in the code, don't plan or write anything yet. Instead:
1. List the questions I need answered by the product owner before this is
   buildable. Only questions whose answer changes what we build.
2. List the edge cases and failure modes this has to handle.
3. Flag anything in the ticket that conflicts with how the app already behaves.
For each question, say what you'd assume if nobody answers, so I can see your
defaults.

Two phrases matter. "Only questions whose answer changes what we build" stops the list from filling up with trivia. And "say what you'd assume" drags the hidden defaults into the open. Every default is a decision the assistant would otherwise have made without telling you.

What came back

Nine questions, each with the reason it changes the build and a default. The first was the most important, and it is one no one had asked:

Q1 When someone pays with a new card at checkout, should they be offered
   "Save this card for next time"?
   Why: Today a card can only be saved on the profile page ... That roughly
   doubles the backend work.
   Default: Out of scope; raise it as a separate ticket. Ask the PO directly,
   because their "so I don't have to type my card" depends on it.

That is a genuine conflict. The ticket promises the customer will not have to type their card, but a customer who never visits the profile page has no saved card, so for them nothing changes. The session listed it again under conflicts with existing behaviour, along with four others, including a nice catch from the API documentation: the endpoint for setting a primary card already described it as "the card selected by default at checkout", a promise the checkout had never kept.

The edge cases were grouped by kind: ownership (a guest sending a card id, another customer's card, a card deleted in another tab), Stripe drifting from the database (a card removed in the Stripe dashboard, a key from a different Stripe account), and payment outcomes (3D Secure, a decline at charge time, a double click on Pay). Each named a specific test card or file where it applied. That list became the backbone of the test plan two steps later.

The answers came from a person

None of the nine answers came from the model. The four that change the build most went to the product owner, with the assistant's default shown first so it was easy to accept or overrule:

Q1    Save a card at checkout?          -> Out of scope, new ticket
Q3/Q5 Where is the card chosen, and     -> Payment step; on a decline, pick
      what happens on a decline?           another card on the same order
Q4    Expired saved cards?              -> Shown, disabled, labelled "Expired"
Q8    Which apps?                       -> Backend + React only

Here every answer matched the default. That is not a sign the step was unnecessary. The defaults were sensible because the code was well understood, but "sensible" is not "agreed". Q3 alone decided the architecture: choosing the card on the payment step, after the order exists, is what forced the design to update an existing PaymentIntent rather than create one. Had the product owner said "details step", the backend would have been simpler and a decline would have meant starting a new order. Both are reasonable. Only one is what they wanted.

The remaining five questions (preselecting the primary, re-entering the CVC, one-click or a confirm button, managing cards from checkout) took the defaults, and that was written down as a decision with a name next to it, so it can be challenged later rather than discovered later.

Why the model should not answer them

It would be easy to skip the product owner and accept the defaults directly. Three reasons not to. The assistant optimises for a coherent design, while the product owner optimises for customers and the business, which it cannot see. Its defaults lean toward what is simplest to build, which is not always what is right to ship. And when a decision goes wrong later, "the AI assumed it" is not an answer anyone can work with. "The PO chose it on the 4th, here is why" is.

The assistant's real contribution here was speed and coverage: a list of nine pointed questions, grounded in the code, in about a minute. Writing that list by hand is the part of requirements work people most often skip.

When the product owner cannot be reached, do not let the work stall and do not let the defaults slide in unnoticed. Build on the defaults, list them at the top of the pull request as open decisions, and keep each one easy to reverse. A decision that is visible and cheap to undo is fine to make provisionally. One that is buried in the code is not.

Before you accept

  • Did you ask for questions and defaults, not for a solution?
  • Is every default either confirmed by the right person or recorded as an explicit decision?
  • Did you look hardest at the conflicts with existing behaviour? That is where tickets are most often wrong.
  • Does every edge case name a concrete trigger (a test card, a file, a sequence of clicks)?
  • Did any answer quietly change the architecture? Make sure the person who gave it knows.
  • Are the answers written down where the planning step will read them?