AI-assisted engineering · 7 min read
The AI Wrote the Feature. Here Is What I Would Review Before Merging.
Review AI-generated code through authorization, failure handling, dependencies, and meaningful tests.

The pull request that looks finished
Imagine opening a pull request after lunch. An AI coding assistant has implemented CSV-based invitations for a workspace. The page has a drag-and-drop area, a preview table, and a clean success message. The description lists tests, accessibility, and error handling. The diff looks organized.
You upload a small file and it works. The temptation is to merge while the feature still feels pleasantly simple.
Then a teammate asks, “What happens if I click Invite twice because the first request is slow?” Another asks whether a member can change the workspace ID in the request. The happy-path demo has not answered either question.
This is a fictional code-review walkthrough. It does not describe a patch from a particular repository. Its purpose is to show where I would spend review attention when generated code arrives faster than a human can comfortably inspect every line.
I would begin with the effect of the feature. It reads user-controlled data and sends invitations to other people. That means the relevant boundaries include identity, parsing, bulk execution, retries, and partial completion. None of those is settled by a polished component or a passing snapshot test.
The assistant may have done most of the implementation correctly. The reviewer still needs a model of what the change can do. Without that, review becomes a search for suspicious-looking syntax rather than a check of the product's actual behavior.
Trace one request all the way through
Start at the upload control and follow the data through parsing, preview, confirmation, and execution. Identify where workspace membership is checked and where the destination workspace is resolved.
A disabled button is not authorization. The server must reject an unauthorized request even if someone bypasses the interface. Likewise, a model-generated comment saying “validated input” is not evidence that validation covers the relevant boundary.
For this feature, I would check file limits, row limits, email normalization, duplicate handling, and whether the parser safely treats cells as data. Each check should correspond to a plausible failure, not a generic checklist pasted into the PR.
Review the effect before the implementation style
Does clicking twice send invitations twice? What happens if the server processes half the file and then times out? Can a user tell which rows succeeded without retrying the whole batch?
Look for stable operation identifiers, resumable progress, and an honest partial-failure response. If retries can repeat external actions, tests that assert only “returns 200” are not telling you much.
A well-factored component is helpful. It does not compensate for an ambiguous execution model. I would settle the business behavior first, then discuss naming and structure.
The test that agrees with the bug
Our imaginary patch includes a test that mocks the invitation service, submits two addresses, and asserts that the service was called twice. It is a reasonable unit test for part of the flow. It does not establish that the right people were invited once to the right workspace.
Suppose the server accepts workspace_id directly from the browser and never checks membership. The test still passes. Suppose a retry repeats invitations already accepted by the provider. The test still passes. The mock has removed the boundary where the failure would become visible.
I would add tests at the appropriate integration boundary using controlled records and a fake external service. A request from an unauthorized member should fail before sending anything. A repeated operation should not create new invitation records. A file containing one bad row should produce the documented partial-success or all-or-nothing behavior.
The point is not to ban mocks. It is to understand which claim each test supports. A parser unit test can use small fixtures. An authorization test needs to exercise the authorization decision. A retry test needs an observable destination state.
Then I would read the implementation again with those behaviors in mind. Is there a stable operation identity? Is the server deriving the caller's scope? Are validation errors attached to the correct rows? Can the user recover after a partial failure without guessing what happened?
This second pass is usually more focused than the first. The reviewer is no longer asking whether the code looks plausible. They are checking whether the implementation matches a small set of explicit promises.
Ask what the tests would catch
Tests written alongside generated code can mirror the implementation's assumptions. Read the assertion and name the mistake it would detect.
For the CSV feature, useful tests include an unauthorized workspace, a malformed row, an oversized upload, duplicate addresses, and a timeout after some invitations were accepted. Check the resulting invitation records, not just the response message.
Run relevant existing tests as well. A new happy-path test can pass while a shared validator quietly breaks another flow. Keep the test evidence tied to the exact revision being reviewed.
Inspect dependencies and execution boundaries
A small feature should not acquire a large dependency tree without a reason. Check new packages, install scripts, lockfile changes, and whether a dependency is needed at runtime or only during development.
When coding agents execute generated code, keep their environment scoped to the task. Anthropic's sandboxing discussion is useful context for separating tool execution from broad machine access. That helps protect the development workflow; it does not replace application security review.
Do not put production credentials in the test setup just to make an integration test convenient. Use an appropriate isolated environment with controlled effects.
Give the reviewer a reproducible route
The PR should explain the user-visible behavior, the difficult failure case, and the checks that actually ran. Include a short manual path when the change depends on browser behavior.
For this example: upload a file with a valid row and an invalid row, inspect the preview, confirm once, and verify that only the intended invitations exist. Then retry the operation and inspect the ledger again.
AI can make producing a patch much faster. The merge decision still depends on whether the change is understandable, bounded, and supported by evidence. I want the review to leave the next engineer with fewer questions, not merely a green check beside a large diff.
What I want the merge decision to mean
Before merging, I would ask the author or assistant to demonstrate the difficult path, not just the successful one. Slow the destination service. Repeat the submission. Include a malformed row. Attempt the request with a user who lacks permission.
The review should leave a record of what was tested and what remains dependent on a live integration. If a browser behavior was checked manually, say that. If an external provider was simulated, say that too. Precision makes the evidence useful to the next person investigating a failure.
There is a balance to strike. A small reversible presentation change does not need the same scrutiny as bulk invitations. Review effort should follow the consequences of the change. The question is where a mistake can cross a boundary, not how many lines the assistant wrote.
The best version of this workflow still benefits from AI speed. The assistant can implement the first draft, help construct awkward cases, and respond quickly to concrete review findings. The human reviewer can spend less time on mechanical editing and more time deciding whether the behavior is appropriate.
A merge should mean that the team understands the change well enough to own it. It should not mean the description sounded professional or the test suite contained the right buzzwords. Fast code generation makes that distinction more important, because the amount of plausible code can grow much faster than shared understanding.
Sources & further reading
Worked scenarios are illustrative. Technical references were checked on September 10, 2026.
Working through a similar problem?
Tell me what you are building and where it gets stuck.
Let’s talk ↗

