An engineer says the behaviour is intended. A customer says it is broken. Each is reporting a fact about themselves, and neither classifies the report. A bug is behaviour that contradicts a written expectation. Where nothing was written, the report is a decision the product owner has not made yet, and it stays a dispute until somebody makes it.
“Works as designed” is a claim about a document
When an engineer closes a report as intended behaviour, the sentence asserts that a design exists and that the behaviour matches it. Ask to see the design. In a team that has been shipping for a while the answer is frequently a commit message, a chat thread, or a memory of a conversation in which somebody decided the export would round to two decimals. That is a design in the engineer’s head, and the customer was never party to it.
None of this is an accusation of bad faith. The engineer is right that the code does what it was written to do. What they cannot know from inside the codebase is whether anybody promised the customer something else, and a software bug is defined against the promise, never against the code. Code always does what it does.
So the first move on a disputed report is to find the written expectation, if there is one: the acceptance criterion on the story, the help article, the label on the button, the error message the customer should have seen. Any of those is a document a customer could reasonably have read. A commit message is not.
Three answers, and the third is the common one
A disputed report can be classified in exactly one of three ways, and the classification follows from whether a written expectation exists and what it says.
| The report | Classification | What happens next | Who decides |
|---|---|---|---|
| Contradicts a written expectation the customer could have read | Bug | Severity from the evidence, priority against the sprint, a fix | The engineer, once the expectation is pointed at |
| Matches the written expectation; the customer wants something else | Feature request | The backlog, with the customer told which stage it sits in | Product |
| Nothing written either way | Not yet classifiable | A decision about what the behaviour should be, written down, and then one of the rows above | Product, and nobody else |
Rows one and two rarely cause the argument. When the help article says the export rounds to two decimals, a customer who wants four has a feature request and knows it. When the acceptance criterion says the total includes tax and the export omits it, the engineer has a bug and knows it. The heat is in row three, and row three is where most disputed reports live, because most behaviour in a product was never specified in a place a customer could read.
One class of report skips the table. A crash, a failed request, a lost record or an error on the screen contradicts an expectation nobody has to write down, and is a bug whatever the documentation says or omits. Row three is for behaviour that completed and is disputed.
The failure mode is to force row three into one of the others. Called a bug, it puts a product decision in an engineer’s fix queue, and the engineer makes the decision by choosing what “fixed” means. Called a feature request, it tells a customer that the thing that broke their invoice is a nice-to-have. Both are the same mistake wearing different labels: a decision made by classification instead of by deciding.
Deciding first makes the classification stable
The way out of row three is to make the decision the report exposed. Should the export include tax? Somebody with authority over the product answers, writes the answer where the next reporter can read it, and only then is the report classified: a bug if the current behaviour contradicts the new sentence, a feature request if it matches it and the customer wanted otherwise.
This is the part that feels slow and is the opposite. A report classified without a decision comes back. The next customer to hit the same behaviour opens the same dispute, the engineer says the same thing, and support reopens the same thread. Once the expectation is written, the second report is classified by anybody who can read, because the answer is a sentence somebody can point at. Acceptance criteria written before the work does this for new features; for behaviour that predates the criteria, the disputed report is the moment the criterion gets written.
The distinction between an issue and a bug earns its keep here. Everything a customer sends is an issue. Only the subset contradicting a written expectation is a bug, and the classification is a property of the issue plus the document, never of the issue alone.
What the report has to carry before anybody argues
Many disputes start because the report describes an outcome and the engineer tests a behaviour. “The invoice total is wrong” is an outcome. Whether it is a bug depends on what the customer did, what they expected the total to be, what the screen showed, and whether the request behind it failed or returned a number the customer disagrees with. Those are four different reports and only some of them are bugs.
So before the classification argument, the report needs expected and observed, in the customer’s words, and the conditions around them. The conditions are the half a customer cannot supply, and asking them for a browser version is a reply that costs a day. When the report is filed from the page, evidence capture puts the network log on the ticket, each request with its status, beside the browser and viewport the customer was using, and the engineer reads whether the request behind the total failed or returned a value the customer disputes. A failed request is a bug in any row. A completed one whose value the customer disputes is a row-three dispute.
Every row-three report costs product one decision
Row three needs product, every time, and no support lead can staff that away. An engineer cannot classify it, because they would be deciding what the product does from inside the fix queue. A support agent cannot classify it, because they would be deciding what the product promises from inside a ticket. The person who owns what the product should do has to spend time on each report that lands in the unspecified row, and that time cannot be scheduled away by a better template or a faster tool.
What the process can do is make each such report cost one decision rather than several. It arrives with the evidence, so the question is about what the behaviour should be rather than about what happened. The decision is written where the next reporter can read it. And the customer who raised it watches the report move through its stages instead of being told “working as intended” and hearing “go away”, which a client portal showing the stage and the comments marked for them makes routine. The dispute is between the product and a sentence nobody had written, and the engineer and the customer are both standing in for it.