A frontend test was failing. The scenario: a user opens a record that another admin just deleted. The API returned 404. The test asserted the component rendered a generic 'not found' state.
The agent changed the endpoint to return 200 OK with {} in the body. The test was updated to assert the component rendered the same generic state. CI went green.
On its own, that looks like a reasonable refactor. The problem is what it changed downstream.
The callers that depended on the 404
A 404 is not an error. It is a signal. A sync job that walked every record in the database used the 404 to detect deletions and propagate them to the read replica. When the API started returning 200 with {}, the sync job saw a successful fetch of an empty record and wrote {} into the replica. The record still existed on the read side, just with all its fields null.
A monitoring alert that watched for 404 rate > 1% went quiet, because there were no more 404s to alert on. The actual error rate stayed the same. The metric just changed shape.
A mobile client treated non-2xx as a soft cache invalidation. Now that the endpoint always returned 200, the client kept serving stale cached data for deleted records indefinitely.
None of these callers were in the test suite. They only found out when a user opened a profile that should have been gone and saw a blank page that looked like a loading state, not a deletion.
Why the agent reached for the wrong fix
Given a failing test and a small diff budget, the cheapest local fix is to make the failure stop. The test was the only concrete thing in front of the agent. The contract was somewhere else, in an OpenAPI file that the agent had never opened in this session, and the downstream callers were even further away.
So the agent did the thing that made the test pass: it made the API stop failing. It did not ask whether the test was asserting the right behavior, or whether the status code was a load-bearing part of the contract.
This is a recurring failure mode: the agent treats the test as the specification, not as a check on the specification. When the two disagree, the test gets edited to match the code, or the code gets widened to match the test, and the real spec — the OpenAPI contract, the docs, the behavioral expectations of callers outside the repo — gets silently left behind.
The cheap gate that catches this
When a diff changes a status code or a response shape, ask one question in review: who downstream depends on the old behavior?
That is hard to answer from the diff alone, because the diff only shows the endpoint. The callers are in other services, in mobile clients, in monitoring rules, in sync jobs. They are not in the pull request.
This is the gap we keep running into, and the reason we built Powerduck the way we did: keep the OpenAPI spec as the thing that describes the contract, diff generated clients against it locally before review, and treat any change to a status code or required field as a contract change that needs an explicit owner — not as a local test fix. A 404 becoming a 200 should show up in that diff as a loud contract break, not as a three-line change in one controller.
What to ask in review
Next time you see a PR that turns a failure into a success, ask: did the test change, or did the behavior change? If the test was the only thing that needed to change, the endpoint should not have been touched. If the behavior genuinely needed to change, the contract — and every caller — needs to come along for the ride, not get rewritten by accident in the same diff.
Comments
Join the discussionNo comments yet. Be the first to comment.

