When Copilot only completed two or three lines at a time, I did not think much about code authorship. The IDE suggested a condition, I pressed Tab, changed something, and moved on. Even if half a method came from autocomplete, the decision was still obviously mine: I knew what I wanted to do, I saw the code appear, and I understood roughly every line.
Coding agents made that boundary much less obvious. Now I can describe a task in plain language and, a few minutes later, receive several new classes, a migration, tests, and a finished diff. Sometimes I did not physically type a single line. If that code later fails in production, the natural question is: who is responsible? Me, the model, the people who built the model, or the reviewer who opened the pull request and clicked Merge?
I think two different questions are often mixed together here: who produced the text and who decided that the text belongs in the running system.
AI changed the first question radically.
It barely changed the second.
If I ask an agent to add rate limiting, inspect the result, and ship it, it matters very little who pressed the keys. The code entered the system because a human decided to keep it there.
That is where ownership begins.
Authorship has become a slightly strange concept
Suppose an agent generated this method:
public function canViewInvoice(User $user, Invoice $invoice): bool
{
return $invoice->userId() === $user->id();
}
I did not type it. Maybe I did not choose the method name either. But before merging it, I checked how invoice authorization works in the rest of the codebase and decided that this rule belongs here.
Formally, the text was produced by AI. In practical engineering terms, that distinction quickly loses importance.
A future developer investigating authorization will not care which model generated the method. During an incident, nobody is going to invite the model that created the code into the call. Production code outlives the LLM session that produced it.
That is why the boundary between “human-written code” and “AI-written code” seems less and less useful to me. After merge, it is simply part of the codebase. Some parts were written by hand, some completed by Copilot, some generated by an agent, some copied from a library.
The more important question is whether someone on the team understands why this code exists and why it is designed this way.
I would test ownership in a very simple way
The author of a pull request should be able to explain the change without relying on the agent's summary.
Why was this new service introduced?
Why this dependency?
Why is the transaction boundary here?
What happens if the request is repeated?
Why did we not extend the existing abstraction?
Why is this timeout value acceptable?
If the answer is:
I don't know. Cursor did it that way.
then the change is not ready to merge.
That is not a criticism of Cursor. It is a missing ownership problem.
This rule works regardless of how much code AI produced. A developer can manually write five hundred lines and understand them poorly. Another developer can let an agent produce almost the entire diff, then study it, refactor it, test the edges, and understand the final design better than if they had typed every line themselves.
In 2026, Debian had a similar discussion around LLM-assisted contributions. The practical principle is familiar: using AI does not remove responsibility from the person submitting the change. The contributor is still expected to understand what they are sending and to make sure it meets the project's quality and legal requirements.
The tool can be almost anything.
A human still says: this work is acceptable.
Merge now carries a little more meaning
Before coding agents, implementation itself forced a developer to spend time inside the code. While writing a feature, you naturally saw adjacent classes, old conditions, strange tests, and implicit assumptions. Even if you were not deliberately studying the system, writing created a certain amount of understanding.
An agent can skip that path. It returns a polished diff touching seven files, with reasonable names, tests, and a green CI pipeline.
The understanding that used to appear naturally during implementation now has to be acquired intentionally.
Looking at the code is not enough. You need to reconstruct the decision flow, understand the scope, identify the business rules, and inspect failure paths.
This makes Merge more than the final button in a pull request. It is the point where a developer adopts the change into their engineering model of the system.
GitHub and other platforms can automate more of the work before that point. AI can propose the change, update it after comments, and even perform a first-pass review. The final acceptance decision still belongs to a developer or a process explicitly designed by the team.
Tests do not remove the ownership question
AI introduces an interesting problem with tests. Agents usually write them willingly alongside the implementation, so a pull request can look especially convincing: the feature exists, coverage is there, and everything is green.
But the implementation and the test can share the same wrong assumption.
Suppose the rule is:
The discount is valid through the end of September 10 in the user's local time.
The model interprets it slightly differently and writes:
$isActive = $now <= new DateTimeImmutable('2026-09-10 23:59:59');
Then the same model writes a test for exactly that boundary.
We get a very neat pipeline:
misunderstood requirement
↓
wrong implementation
↓
test written for that implementation
↓
green
There is no contradiction inside the change.
The problem is outside it.
That is why I do not treat tests written by the same agent at the same time as the implementation as independent proof of correctness. They need to be read as part of the proposed solution.
Especially where money, permissions, security, or complex business invariants are involved.
OWASP has been moving in the same direction for AI-assisted development: an AI-assisted change should still have a concrete human owner, pass human review, and meet ordinary security and maintainability requirements. The fact that a tool generated the code does not lower the bar.
This is also why “let one AI write it and another AI review it” is useful but incomplete.
The second agent may find a bug.
A third may find another.
Static analysis may find a fourth.
None of them necessarily knows the old business rule that was never written down anywhere.
AI-written code does not need a separate quality standard
I do not think we need one quality category for human code and another for AI code.
The ordinary questions are still sufficient.
Is it correct?
Is it secure?
Can it be maintained?
Does it fit the architecture?
Are the tests meaningful?
Did it introduce an unnecessary dependency?
Will another engineer be able to understand it a year from now?
If the answer is no, the provenance does not make the problem smaller.
And the reverse is also true. A good solution should not be rejected simply because an agent wrote most of it.
The quality bar should stay the same. What changes is the path by which we establish confidence.
With AI-generated code, I pay more attention to certain failure modes: hallucinated packages, outdated API versions, reimplementation of an existing helper, unnecessary abstractions, and polished code that hides a more basic question — was this change needed at all?
The final standard, however, is the same standard we would apply to any production change.
Responsibility does not belong to one developer alone
It would also be wrong to reduce ownership to the single person who clicks Merge.
Software delivery is a system.
There is the author or owner of the change.
There is the reviewer.
There is CI.
There are architecture rules, access controls, deployment processes, and organizational policies.
There is a team lead or engineering manager deciding how work is accepted.
And there is a company that chose which AI tools may access which code and data.
If an organization allows an autonomous agent to modify a project, install dependencies, open pull requests, and merge after another AI approves them, responsibility cannot later be reduced to one developer who happened to be nearby. That is a property of the process the organization designed.
I would separate two levels.
A human is responsible for a change they consciously accept and submit.
The team and the organization are responsible for the system that determines how changes may be produced and accepted.
If an agent has production credentials, that is not a prompt problem.
If a thousand-line pull request can reach production without anyone understanding it, that is not a model problem either.
If private source code is sent to an external service without a policy decision, responsibility lies above the individual autocomplete session.
AI does not remove engineering management. It adds a new productive actor that has no organizational responsibility of its own.
Autonomous agents make this especially visible
As long as AI only proposes code, the boundary is relatively simple.
Agents gradually introduce real actions. They can run shell commands, install packages, change database migrations, work with GitHub, create branches, and open pull requests.
At some point, the agent is no longer just writing text.
It is doing things.
Then it becomes more useful to think about responsibility the same way we already think about permissions in any other system.
If a service does not need to delete data, it does not get delete permission.
If an agent only needs to read a repository and create a branch, it does not need production credentials.
If an operation is irreversible, require confirmation.
Instead of trying to teach a model to “never do anything bad,” it is much more reliable to constrain its action space architecturally.
OWASP recommends human ownership, explicit approval before merge, and an audit trail showing who accepted a specific AI-assisted change.
This feels very familiar.
We do not build ordinary backends on the assumption that developers will never make mistakes. We add access control, transactions, constraints, and audit logs.
Agents deserve the same treatment.
If an agent can perform a dangerous action, the architecture should account for the probability that it will eventually make a mistake.
Licenses and data remain separate concerns
There is another layer that should not be confused with engineering ownership: code provenance and data usage.
If generated code contains a suspiciously specific implementation, a developer cannot simply say, “I did not copy it; the model generated it.” Open-source licenses, company policy, service terms, and local law still matter.
The exact legal answer depends on the provider, contracts, jurisdiction, and the kind of code involved. There is no universal rule that fits every company.
From an engineering perspective, the principle is simpler: code accepted into the project needs acceptable provenance, and data sent to the model must be permitted to leave the system under the rules you operate under.
AI changed the tool.
It did not remove the need for a decision.
Should we mark code as AI-generated?
I am not sure this will remain particularly useful in the long term.
A comment like:
Generated by Claude
inside production code rarely helps the future reader.
PR metadata may be more useful. It can help a team understand which task types are handled with AI, how often AI-generated pull requests return from review, how large they are, or whether they correlate with particular bug classes.
That is useful process data.
Inside the codebase itself, I care much less.
Two years later, “why does this algorithm work this way?” will matter more than “which model wrote it?”
There may still be good reasons to preserve provenance for security, compliance, or analytics. I just would not turn AI-written code into a separate species of code.
Good production code should be understandable without access to the chat that produced it.
I ended up with a fairly simple rule
I do not care very much who typed the characters.
If I accept a change, I need to understand it well enough to live with it after the AI session disappears.
That does not mean memorizing every line. It means understanding the engineering decision.
Why is the logic here?
What constraints does it preserve?
What trade-off did we choose?
How can it fail?
What happens when the requirement changes?
If nobody can answer those questions, the problem is not that AI wrote the code.
The problem is that code is entering the system without an owner.
That is much more dangerous.
Instead of a conclusion
A few years from now, “who wrote this code?” may become a less interesting question than it already is.
The number of physically typed characters was never a particularly good measure of engineering work. IDEs generated boilerplate. Frameworks created files. Formatters rewrote them. Compilers did enormous amounts of work on our behalf.
AI simply extends the list. It can now produce implementation, tests, migrations, documentation, and review fixes.
Someone still has to decide that the change belongs in the system.
That is where the meaningful authorship of the engineering decision increasingly moves: not to the moment when text appears, but to the moment when a human understands the change and says yes.