"Done" Doesn't Mean Built as Described. Here Is How Oracus Checks Every Ticket Against the Code That Shipped
A ticket describes what should happen. A PR merges, someone flips the ticket to Done, and nobody checks that the code actually did what the ticket asked. Oracus reads each acceptance criterion the moment a ticket closes, verifies it against the code, specs, tests, and config that shipped, and comments back with evidence, flagging anything it can't confirm.
A ticket is a promise. It says what the feature should do, often as a short list of acceptance criteria. A developer picks it up, writes the code, opens a pull request, and it merges. The board integration flips the ticket to Done. Everyone moves on.
Nobody checks the one thing the ticket was for: did the code that shipped actually do what the ticket described?
Most of the time it did. But “most of the time” is exactly the problem. The gaps are quiet. A criterion gets dropped because it turned out to be harder than expected and the ticket never got updated. A requirement is half-built and reads as finished in a demo. An assumption in the ticket, such as “rates refresh daily,” turns out not to be true of the code, and no one notices until a customer does. Done became a status a card moves through, not a statement anyone verified.
This post is about why that gap is structural rather than a discipline problem, and what changes when a system re-reads every ticket against the code the moment it closes.
Why “Done” drifts from “built as described”
The intent and the implementation live in two different places, owned by two different people, and nothing reconciles them at the moment that matters.
The ticket holds the intent. It was written before the work, by someone thinking about the desired behavior: the acceptance criteria, the edge cases, what the feature is supposed to guarantee. The code holds the reality. It was written during the work, shaped by what was actually feasible, what the existing system allowed, and what the developer had time for. Those two are supposed to match. Whether they do is never checked against the ticket, because checking it is slow, manual work that no role is set up to do at scale.
QA can spot-check the important tickets, but not every one, against every diff, every sprint. The product owner who wrote the criteria has moved to the next thing. The developer believes it is done, which is why they marked it done. Code review looks at whether the code is good, not whether it matches a ticket the reviewer may not have read. So the acceptance criteria, the actual definition of the work, get written once and then never compared to what shipped.
The faster a team ships, the wider this gap grows, and the more it costs. A dropped criterion caught at merge is a comment on a ticket. The same gap caught in production is an incident, a support thread, and a customer who was told the feature does something it doesn’t.
Oracus already links the ticket to the code
Oracus exists to answer questions about your product by ingesting the sources that hold the truth: your code repositories, your Jira and Linear tickets, your tests, your specs and config. It embeds them and links them. This ticket maps to this service, this test covers this behavior, this code implements this capability.
That linked picture is exactly what verifying a ticket requires. To check whether a feature was built as described, you need the ticket’s criteria on one side and everything the repo actually contains on the other: the functions, the specs, the tests, and crucially the data and config files, because that is where a lot of real behavior lives. Oracus already holds all of it, cross-referenced. So it can do the comparison no single person has time to.
What happens when a ticket moves to Done
When a ticket closes, Oracus re-indexes the linked repository so it is looking at the code that just shipped, not a stale copy. Then it does three things.
First, it reads the ticket and decides whether the description is even specific enough to check. Vague tickets like “improve performance” or “clean up the checkout flow” are not verifiable against code, and Oracus says so rather than inventing a verdict. This matters: a tool that confidently grades unverifiable tickets is worse than no tool.
Second, it breaks the ticket into discrete acceptance criteria, one checkable claim at a time, and for each one searches the shipped code, specs, tests, and config for evidence. It then judges each criterion as confirmed, not confirmed, or not verifiable from the available evidence, and it cites exactly what it looked at.
Third, it writes the result back onto the ticket as a comment, and flags the ticket for review if anything failed to confirm. The comment is grounded. Every verdict points at the specific file or function it was based on, so the reader is not asked to trust a black box. They can see the evidence.
Throughout, Oracus is deliberately conservative. When it cannot find enough evidence to be sure, it says “can’t confirm” rather than guessing either way. A verification tool earns trust by never crying wolf and never waving something through on a hunch. The verdicts you see are the ones the evidence supports.
A concrete example
Take a ticket asking a currency service to support two new currencies, with rates that are “refreshed daily from the European Central Bank feed,” and to make the conversion table data-driven instead of a fixed list.
When that ticket closes, Oracus breaks it into its parts and checks each against the code that shipped:
- The two currencies are present. Confirmed. Oracus finds them in the service’s conversion data file, with their rates, and cites that file.
- The table is data-driven. Confirmed. It finds the function that loads the conversion data from an external file rather than a hard-coded list, and cites it.
- Rates refresh daily from the ECB feed. Not confirmed. The service reads a static data file. There is no scheduler, no call out to an external feed, nothing that refreshes anything on a daily basis anywhere in the code. The ticket claimed a behavior the implementation does not have.
That third line is the whole point. Two of the three criteria were built exactly as described. The one that wasn’t is the one a demo would never reveal. The currencies show up, the conversion works, everything looks done, and it is precisely the kind of quiet gap that surfaces months later when someone asks why yesterday’s rates are still today’s. Oracus catches it at the moment the ticket closes, on the ticket itself, with the evidence attached.
What this changes
For an engineering leader, the shift is that “Done” starts carrying a verified meaning again. Every closed ticket gets read back against the code that shipped, automatically, without adding a step to anyone’s day. The flagged ones, the handful where the code and the ticket disagree, rise to the top, so review effort goes where it is actually needed instead of being spread evenly across work that was fine.
For QA, it is leverage. Instead of manually reconciling tickets against diffs one at a time and only for the highest-risk changes, every ticket gets a first-pass check, and QA spends its judgment on the exceptions Oracus surfaces rather than on the search that finds them.
The promise a ticket makes is worth keeping. Oracus makes keeping it something that happens on its own, the moment the work is called done.