AI Code Review for API Breaking Changes: Catching the Bug That Is Not in the Diff
A renamed field is correct, tested and green inside its own repository, and breaks a consumer nobody in the PR can see. What counts as breaking, the seven questions a reviewer must ask, what a model can verify from the repository, and how to make it run on every interface change.

The most expensive bugs a review can miss are the ones that are not bugs in the diff. A renamed JSON field, a parameter that became required, an enum value that quietly went away: each is a correct, tested, green-CI change inside its own repository, and each breaks a consumer that nobody in the pull request can see. Breaking API changes are the canonical example of a defect whose evidence lives outside the lines that changed, which makes them both the thing AI code review is best positioned to catch and the thing a diff-only reviewer is least likely to notice.
This post is a working definition of what counts as a breaking change across the interfaces a typical service exposes, a checklist a reviewer should run on any PR that touches one, the parts a model can verify from the repository, and the parts it cannot. Where PURA does something specific we say so; the rest applies to any reviewer with the repository open.
What “breaking” means, interface by interface
Teams argue about breaking changes because they only agree on the obvious cases. A removed endpoint is breaking. Everything else depends on the interface and on what consumers were allowed to assume. A reviewer needs the fuller list:
- HTTP and REST: removing or renaming a path, field or query parameter; making an optional input required; narrowing an accepted type; changing a status code that callers branch on; changing error body shape; tightening validation that used to let existing data through; changing pagination or default sort.
- GraphQL: removing a field or type, making a nullable field non-null on input, changing an argument’s type, removing an enum value. Adding a non-null field to an output type is usually safe; adding a required argument never is.
- gRPC and protobuf: reusing or renumbering a field tag, changing a field’s wire type, removing a field without reserving its number, renaming a service or RPC, changing a message from optional to required semantics in application code.
- Events and queues: changing the shape of a published message, renaming a topic, changing the meaning of an existing field, altering ordering or delivery guarantees that a consumer relies on.
- Libraries and SDKs: anything semver calls a major change: removed or renamed exports, changed signatures, narrowed accepted types, widened return types, new exceptions, changed defaults, and behaviour changes that a caller could observe.
- Databases shared across services: a column or table that another service reads directly is an API, whether anyone admits it or not. That overlaps with migration review, which has its own checklist.
Two subtleties catch experienced engineers. First, loosening is not always safe: widening what an endpoint returns can break a strict deserializer on the consumer side, and relaxing validation can let data through that a downstream system rejects. Second, behaviour is part of the contract. An endpoint that used to return results sorted by date and now returns them sorted by relevance has not changed its schema and has broken every client that took the first result.
The checklist a reviewer should run
1. Is an interface actually being touched?
The first job is detection, because most breaking changes are not labelled. A reviewer should treat any change to route definitions, OpenAPI or GraphQL schema files, protobuf files, serializer or DTO classes, event schemas, public type definitions and exported functions as an interface change, and say so explicitly in the review. Half the value of the review is the sentence “this PR changes the public shape of X” appearing where a human will read it.
2. Is the change additive, or does it remove or narrow?
Additive changes (new optional field, new endpoint, new enum value on output) are usually safe and should be waved through quickly. Removals, renames, type narrowing and new required inputs are breaking by default. A rename is the worst case: it is a removal and an addition with no overlap window, so unless the PR keeps the old name alive it breaks every consumer at the moment of deploy.
3. Who consumes this interface, inside the repository?
This is the check that requires the whole repository rather than the diff, and it is where a diff-only reviewer nods a disaster through. For a renamed field, the reviewer should search for every reader and writer of the old name: other services in a monorepo, client code, fixtures, generated clients, documentation examples and tests. The context post explains why the whole repository has to be available for this; the monorepo post covers the case where the consumers are in sibling packages.
4. Who consumes it outside the repository?
The reviewer cannot see other repositories, mobile apps in the field or third-party integrations. What it can do is check whether the interface is documented as public, whether a changelog or API version exists, and whether the PR claims to have coordinated with consumers. The right output is a question, not a verdict: “this endpoint is in the public OpenAPI document; has the change been communicated and versioned?”
5. Is there a compatibility window?
The safe pattern for a breaking change is the same expand-and-contract shape as a schema migration: add the new thing, support both, migrate consumers, remove the old thing in a later PR. A reviewer should flag a PR that removes and adds in one step, and should ask where the deprecation notice, the dual-write or dual-read, and the removal date live.
6. Does the version or changelog reflect it?
For a library, a breaking change without a major version bump is a bug in the release, not just in the code. For a service with versioned endpoints, the question is whether the change lands in a new version or mutates an existing one. A reviewer can verify this mechanically: if the PR removes an export and does not touch the version or changelog, say so.
7. Are the contract tests and generated clients updated, and do they pass for the old shape?
Updated tests prove the new shape works. They do not prove the old shape still works for consumers that have not migrated. A reviewer should look for consumer-driven contract tests, recorded fixtures or golden files, and notice when the PR updates them wholesale, which is the usual way a breaking change is made to look green.
What a model can verify, and what it cannot
With the repository available, a model does well at the mechanical parts: spotting that a diff touches an interface file, classifying the change as additive or breaking, finding in-repo consumers of a renamed symbol, noticing a missing version bump, and reading a protobuf diff for a reused tag. It also does well at the explanatory part, which humans skip under time pressure: stating in plain language which consumers will break and how, rather than leaving a terse “this is breaking” comment.
It cannot see consumers in other repositories or in deployed apps, it cannot know whether your partner integrations tolerate unknown fields, and it cannot tell whether a behaviour change matters without being told what consumers rely on. For those it should ask, and the review should be structured so the questions are visible. Confident silence is the failure mode to design against; the false positives post covers the opposite failure, where a reviewer flags every additive change as breaking and gets ignored.
Turning the checklist into review rules
Most of the above can be expressed as project instructions for the reviewer. In PURA that means review rules at the repository or team level (the mechanics are in custom rules); the same wording works as guidance for any tool that accepts instructions. Rules that have worked for teams we have seen:
- “Any change under
api/,proto/,schema/or to a file matching*.openapi.yamlis an interface change. Open the review with a one-line summary of what shape changed.” - “Classify each interface change as additive or breaking using the definitions in
docs/api-compatibility.md. For breaking changes, list every in-repository consumer of the old name or shape.” - “For a breaking change, check that the version in
package.json(or the endpoint version) has been bumped and the changelog updated. If not, say so as a blocking comment.” - “For a rename or removal, ask whether a compatibility window exists and where the removal is scheduled. Do not block on this; ask.”
- “Treat changes to default values, sort order, pagination and error shapes as interface changes even when no schema file is touched.”
The blocking-versus-advisory split matters here. A missing version bump on a removed export is a mechanical fact and can block. Whether a compatibility window is needed is a judgement that depends on consumers the reviewer cannot see, and should be a question. The reasoning for that split is in blocking vs advisory review.
Where this pays off
The economics are lopsided. A breaking change caught in review costs one comment and a follow-up commit. A breaking change caught in production costs an incident, a rollback that may itself be breaking, and a week of a partner team not trusting your releases. Most teams have a human who is good at spotting these, and that human is the bottleneck on every API PR. A reviewer that runs the seven questions on every interface change, with the repository open, with the consumers listed, before that human spends their attention on it, is not replacing them. It is making sure the one question they would have asked is already answered.
Frequently asked questions
- What counts as a breaking API change?
- Removing or renaming a field, path, type or export; making an optional input required; narrowing an accepted type or widening a returned one; removing an enum value; reusing a protobuf tag; and behaviour changes a caller can observe, such as default sort order, pagination or error shape. Additive changes such as a new optional field are usually safe.
- Can AI code review detect breaking changes?
- Partly. With the whole repository available it can detect that an interface file changed, classify the change as additive or breaking, list every in-repository consumer of a renamed symbol, and notice a missing version bump or changelog entry. It cannot see consumers in other repositories or deployed apps, so for those it should ask rather than decide.
- What is the safe way to ship a breaking change?
- Keep both shapes alive for a window: add the new field or endpoint, support the old one, migrate consumers, and remove the old one in a later pull request. A reviewer should flag any PR that removes and adds in one step and ask where the deprecation notice and the removal date live.
Ready to put your AI review spend on rails?
Install PURA on your GitHub repos and start setting budgets in minutes — not months.
Install PURA for free