Finding the sentence two engineers would build differently
Most requirements defects are not caused by missing requirements. They are caused by requirements that read as finished, pass review, and mean two different things to two different engineers. Nobody notices until the wrong one has been built.
This one has a user story, three acceptance criteria and an estimate. It was refined, pointed and pulled into a sprint without a question being raised.
As a platform engineer, I want old orders archived, so that the orders table stays performant as volume grows.
The agent does not scan for vague words. It builds every implementation the sentence permits, then runs them against production shape to see whether they agree. Here the first criterion alone yields two.
SELECT id FROM orders WHERE created_at < now() - INTERVAL '24 months';
SELECT id FROM orders WHERE updated_at < now() - INTERVAL '24 months';
Both implementations satisfy every written criterion. Both would pass code review. Both would pass QA, because the test cases were written from the same sentence. The 351,478 orders in the gap are ones created long ago but touched recently — refunds, disputes, warranty claims. Under reading A they vanish from search while still under active handling.
Ambiguity is not vague writing. It is a sentence two competent engineers implement differently, and both are right.
Not a list of unclear words. A list of decisions that are currently being made by accident, each with the consequence of getting it wrong attached.
created_at or updated_at?
351,478 orders differ between the two. If age runs from creation, orders under active dispute disappear from search while agents are still working them. This is the only question of the three that changes the shape of the query.
Internal search only, or every read path?
There are four consumers: the support console, the customer’s own order history, the finance reconciliation export, and the returns service. Excluding archived orders from the finance export changes the month-end numbers. Excluding them from customer history is arguably a regulatory problem. The criterion names none of them.
No criterion mentions open backorders, refunds in flight, or unsettled payments.
Nothing in the story excludes them, so the literal implementation archives them. An order with an open backorder that leaves the active table stops being picked up by the nightly allocation job — a silent failure with no error and no alert.
Once the three are answered, each criterion carries an identifier that survives into the branch, the tests and the review. The question at review stops being “does this code look right” and becomes “which criterion does this satisfy”.
| Criterion | Decision | Satisfied by | Verified by |
|---|---|---|---|
| AC-1 Age threshold | Age runs from updated_at |
ArchiveQuery.olderThan() | ArchiveQueryTest · 4 cases |
| AC-2 Search exclusion | Support console only; finance and customer history unchanged | OrderSearchFilter | SearchExclusionTest · 3 cases |
| AC-3 Nightly run | Unchanged | ArchiveJob | ArchiveJobTest · 2 cases |
| AC-4 Settlement guard | Added — exclude open backorders and refunds in flight | ArchiveQuery.settledOnly() | SettlementGuardTest · 5 cases |
| Left as written | Consequence | When it would surface |
|---|---|---|
| Age from creation | Orders under active dispute drop out of the support console | First support escalation after release |
| Blanket search exclusion | Archived revenue missing from the finance export | Month end, during reconciliation |
| No settlement guard | Open backorders silently leave the nightly allocation job | Never, until a customer asks where their order went |
A fourth criterion was added that nobody had written, and two that existed were given meanings they did not have. The cost of asking was one refinement session. The cost of not asking was a month-end reconciliation and an unknown number of stranded backorders.