Blog
Half Your Bug Reports Are Expected Behavior. Support Can't Tell Which Half.
9 min read
The engineering bug queue has two kinds of tickets. The first kind is a genuine bug — code doing something it shouldn't. The second kind is expected behavior that a customer doesn't understand — plan limits, batch delays, rate limiting, account tier restrictions. Engineers can tell these apart in two minutes by looking at the code. Support can't, because support doesn't have the code. So both kinds flow into the engineering queue, and engineers spend a significant fraction of their triage time writing "this is expected behavior" responses to questions that never needed engineering involvement.
The split is not small. Research on support escalation patterns consistently shows that roughly half of inbound bug reports describe expected behavior. Every one of those tickets consumed support handling time, engineering triage time, and customer waiting time — for a resolution that could have been delivered at intake if anyone had been able to check the code.
What "expected behavior" actually means
A customer who can't export more than 10,000 rows is not experiencing a bug — they're hitting a plan limit that exists in the export service configuration. From the customer's perspective, the feature is broken. From the codebase's perspective, the behavior is exactly correct. The distinction is not apparent from the customer's report — it's apparent from the code.
The same applies to rate limiting (429 errors), batching delays, feature gates, account tier restrictions, and API quota enforcement. All of these produce behaviors that customers describe as broken. All of them are implemented intentionally. None of them are discoverable as "expected" without reading the implementation — which only engineering currently has access to.
What ends up in the "bug report" queue:
Actual bugs (need engineering fix):
-> "Export fails with 500 error for files > 100MB" — bug in size validation
-> "Auth token expires without warning" — missing refresh logic
-> "Dashboard numbers off by 1 day in UTC+8" — timezone offset bug
~45% of reports
Expected behavior users don't understand:
-> "Can't export more than 10,000 rows" — documented plan limit
-> "Email notifications delayed" — batching behavior, by design
-> "API returns 429" — rate limiting working correctly
-> "Can't access admin settings" — wrong account tier, not a bug
~55% of reports
Without codebase access, support sends all 100% to engineering triage.The opportunity cost of triage that shouldn't happen
For each "not a bug" ticket that reaches engineering, the triage process is the same as for a genuine bug: read, locate relevant code, determine nature, write explanation. The difference is that the output is "this is expected" rather than a fix. The time investment is identical. The value delivered to the engineering queue is zero — the ticket shouldn't have been there.
Support escalates questions to engineering that have codebase answers — the expected behavior category is the largest subset of this problem. Plan limits, rate limits, feature gates — all of these are defined in the codebase. All of them are answerable without engineering judgment. All of them currently require engineering time because support can't check the code.
What engineering triage does with "not a bug" tickets:
1. Engineer reads ticket
2. Engineer locates relevant code
3. Engineer checks: is this a bug or expected behavior?
4. Engineer determines: expected behavior
5. Engineer writes explanation back to support
6. Support relays to customer
Total time: 45 minutes per ticket
For 55 tickets/week that aren't bugs: 41 hours/week of engineering time
Annual cost: ~2,000 hours of senior engineering time on non-bugsClassification at ticket creation
Kognita's webhook fires when a bug report arrives. The managed agent checks the reported behavior against the current codebase: is this a plan limit, a rate limit, a feature flag, a tier restriction, or something the code actively enforces? If the reported behavior matches an intentional implementation, the agent classifies it as expected behavior and routes it to the appropriate non-engineering team — account management, customer success, or support — with the relevant codebase context explaining why the behavior is correct.
What a Kognita webhook agent checks on a bug claim:
Ticket: "Can't export more than 10,000 rows — is this a bug?"
Agent queries codebase:
-> Checks export-service for row limits
-> Finds: ExportLimits.MAX_ROWS_STANDARD = 10_000, MAX_ROWS_ENTERPRISE = 500_000
-> This is a plan limit, not a bug
Agent response: "Row export is limited to 10,000 rows on standard tier accounts.
Enterprise tier supports up to 500,000 rows. This is expected behavior.
Routing to account management for upgrade conversation if needed."
Engineering queue: never sees this ticket.
Support: resolves in minutes with accurate context.
Customer: gets a useful answer, not a 2-day wait for "not a bug" response.Engineering never sees it. The customer gets an accurate answer within minutes rather than two days. If the expected behavior is actually a problem for the customer — a plan limit they want removed, a rate limit they need increased — the ticket routes to the team that can have that conversation rather than to engineering to investigate something that isn't broken.
What remains in the engineering queue
When expected behavior reports are filtered at intake, the engineering bug queue contains actual bugs. The tickets that remain are reproducible issues, regressions, edge cases, and genuine defects. The engineers who work the queue spend their time on problems that need their expertise. The signal-to-noise ratio in the queue improves dramatically.
For teams that track engineering time on support, the reduction in "not a bug" escalations produces measurable capacity recovery. That capacity goes back to the engineering work that was being deferred while engineers worked through a queue that was half noise.
Final take
Roughly half of bug reports are expected behavior. The distinction is answerable from the codebase in seconds. Engineering currently makes this determination after the ticket has consumed support handling time and entered the engineering queue. A webhook agent that reads the codebase at intake makes this determination before any of that time is spent — and the engineering queue sees only actual bugs.
Half your bug queue isn't bugs. The codebase knows which half. A webhook agent that reads it at intake sends engineering only the half that needs them.