Skip to content
Fredrin

All posts

GuideFredrin team8 min read

Shipping AI-generated code a client will accept: the review-first workflow

Clients do not reject AI-generated code because a model wrote it. They reject it because it arrives without the things that make any change acceptable: a bounded diff, a stated intent, evidence that it works, and a human who can explain why it looks the way it does. Review-first means producing those artifacts as part of generating the change rather than reconstructing them afterward — which is a workflow decision, not a model setting.

Get that right and the provenance question mostly stops being asked. Get it wrong and no disclosure policy will save the engagement.

Why do clients actually reject AI-generated code?

Ask a client engineer who has rejected one and the reasons are consistent, and none of them is "a model wrote it":

  • The diff is too large to evaluate. Eleven files touched for a change that was described in one sentence.
  • It solves a problem they did not ask about. The model noticed something adjacent and fixed it too, uninvited.
  • It ignores a local convention. Technically correct, visibly foreign to the codebase, which reads as someone who did not look around first.
  • The tests assert the implementation, not the behavior. They pass. They would pass if the feature were wrong.
  • Nobody can explain a specific decision. The one that ends engagements: an engineer is asked why a retry loop is there and answers that it came with the change.

Every item on that list is a property of the submission, not of the author. A junior engineer producing the same diff would get the same rejection. That is the useful reframe: your job is not to conceal the model's involvement, it is to submit work that would pass review regardless of who wrote it.

Do you have to tell the client you used AI?

Check the contract first — some engagements, especially in regulated industries, have explicit terms about it, and that ends the debate.

Absent a term, the workable norm in 2026 is: do not volunteer it change by change, do not conceal it if asked, and never let it become an explanation. "The agent wrote that" is not an answer to a review question. If you cannot defend a line, it is not ready, and that standard is identical to the one you would apply to code you pasted from anywhere else.

The practical risk is not disclosure. It is being caught not understanding your own submission, which costs the trust that the entire role runs on.

What makes a diff reviewable?

Four properties, in rough order of impact:

One intent per change. The change does the thing it says and nothing else. Opportunistic cleanup, however tempting, belongs in its own change — the reviewer cannot separate the risky part from the safe part when they are interleaved.

Small enough to hold in your head. Under a few hundred lines is a reasonable ceiling. Beyond that, review quality falls off a cliff, and the reviewer starts sampling rather than reading. Both of you will pretend otherwise.

Stated acceptance criteria, written before the work. "Uploads over 50MB return 413 with a JSON error body, and the existing multipart path is unchanged." Written first, this is a specification the agent builds toward. Written after, it is a description of whatever happened.

Evidence, not assertion. A test that fails before and passes after. A command with its actual output. A screenshot of the real UI. The claim "this works" carries no information; the transcript of it working does.

How do you review code you did not write?

Differently from how you review a colleague's, because the failure modes differ. A human writes code that is wrong in ways that make sense — they misunderstood the requirement. A model writes code that is wrong in ways that look right, because plausibility is the thing it optimizes.

What that changes in practice:

  • Read the tests first. They tell you what the change believes it is doing. Tests that assert the implementation rather than the behavior are the most common tell that a change is hollow.
  • Check the boundaries, not the middle. The happy path is usually fine. Empty input, the concurrent case, the failure of the thing being called — those are where the confident-and-wrong lives.
  • Be suspicious of unrequested breadth. A change larger than the request means the model decided something. Find what it decided.
  • Verify every external reference. Library versions, API shapes, configuration keys. Confident citation of something that does not exist is a specific and well-known failure.
  • Run it. The single highest-value review step, and the one most often skipped under time pressure.

A rule that saves more time than it costs: if you find yourself reasoning hard about whether a section is correct, stop and ask for it to be smaller. Difficulty understanding is itself the finding.

The tooling side of this — which reviewers exist, what each one actually catches, and why none of them will block a merge for you — is the AI code review guide.

What do you do when the agent is confidently wrong?

Do not argue with it, and do not accept a patch on top of a flawed change. Both produce layered wrongness that is harder to review than the original.

Restate the constraint it violated and have the change redone. "This must not hold the lock across the network call" produces a better second attempt than "that's wrong, fix it," because the first is a specification and the second is a mood.

If the second attempt is also wrong in the same way, the problem is your framing, not the model. Something in the surrounding context — a convention, a constraint, a fact about the system — is not written down anywhere it can read. Which is the next section.

How do you keep the decisions after the engagement ends?

This is the part that separates an FDE who leaves a client better off from one who leaves a pile of code nobody can maintain.

Every engagement generates two kinds of knowledge. Conventions — how this codebase does things — and decisions — why a costly-to-reverse path was taken. Both are usually stored in the engineer's head, and both leave when the engineer does.

Put them in the client's repository, in plain files. A conventions file at the root that any agent reads before touching anything. A decision log where each entry records what was decided, why, and what was rejected. Both in the repository rather than a wiki or a tracker, because the repository is what survives your departure, the vendor change, and the tool you happened to like this year.

There is a compounding benefit while you are still there: written-down context is exactly what stops the agent making the same wrong assumption every week. Every correction you write down once is a correction you never make again.

Does this slow you down?

At first, modestly. Then it inverts.

The cost is a few minutes per change writing acceptance criteria and keeping the scope tight. The saving is every review that takes four minutes instead of twenty, every change that lands the first time, and every conversation you do not have about why something unrequested appeared in the diff.

The compounding effect is the point. Review cost per change is the real ceiling on how much parallel work one person can sustain — the arithmetic is in running five client engagements in parallel. Halving review cost does more for your throughput than any change to how the code gets generated.

Where does tooling help?

Some of this is discipline and no tool provides it. But three parts are genuinely structural.

Scope is enforced by isolation. A change confined to its own branch and its own working directory cannot quietly grow into three changes. Give every unit of work its own worktree and its own agent session and the boundary is physical rather than aspirational.

Review has to be a place, not a memory. Finished work needs somewhere to sit and wait for a human, visibly, so the queue is a thing you drain rather than a thing you hope you remembered.

Rejections must reach the next attempt. When you send something back, the reason should be attached to the work when it resumes — otherwise you re-explain the same objection, which is the most common way review time gets spent twice.

That is the shape of Fredrin: one ticket, one branch, one worktree, one agent session, a review column, and rejection reasons carried forward. It is deliberately not an autonomous agent that returns a finished PR — a human reviews and ships every change, which is the whole argument in Fredrin vs Devin. The wider role context is in the forward deployed engineer breakdown, and the rest of the stack is in the 2026 tool stack.

FAQ

Should I disclose AI use to a client? Follow the contract. Absent a term: do not volunteer per change, never conceal when asked, and never use it as an explanation for a decision you cannot defend.

What if the client bans AI tools entirely? Respect it, and get the boundary in writing — some bans cover sending code to third-party providers, others cover generated code in the product. They are different rules with different workarounds. Guessing here is a contract problem, not a technical one.

How large is too large for one change? As a working rule, a few hundred lines, or anything you cannot describe in one sentence. If describing it needs "and", it is two changes.

Who is responsible if AI-generated code causes an incident? You are. Both contractually and practically, this has never been ambiguous. The tool's involvement does not appear anywhere in the liability chain.

Do tests written by an agent count as evidence? Only if you read them. An agent-written test that asserts the implementation is worse than no test, because it manufactures confidence. Check that it fails against the old code.

What is the single highest-leverage habit? Writing acceptance criteria before the work starts. It converts review from an open-ended judgment into checking a claim against evidence, and it is the difference between reviewing in four minutes and reviewing in twenty.


Fredrin is a desktop kanban for running many AI coding agents in parallel — every ticket gets its own branch, worktree, and agent session, and nothing merges without a human review. Free on macOS and Windows, on the AI subscription you already pay for: fredrin.com.

Written by

Fredrin team

The team building Fredrin — a desktop kanban that gives every ticket its own branch, worktree, and AI agent.