Here's what they look like, what they mean, and how we validated the agent attribution before publishing.
This week we ran the Rosentic engine on eight production codebases from companies that are public about how they build software: Inngest, Polar, Hatchet, Trigger.dev, Hoppscotch, React Email, Unkey, and Drizzle ORM. The engine looked for one thing across all of them: cross-branch compatibility conflicts that CI doesn't catch.
In the six normal repos it found 1,124 conflicts. 850 of them (76 percent) came from branches authored by AI coding agents. The other two repos (Drizzle ORM and Unkey) had 65,989 conflicts between them, but neither has measurable agent activity. We exclude those two from the headline because they're outliers driven by massive human refactors, not by agent patterns. More on that below.
Every one of these conflicts existed in a production codebase right now. Every branch involved had passed CI. Every PR involved had passed code review. None of them showed up as a problem until we looked across branches at the same time.
The first version of this analysis got two repos wrong. We caught both before publishing. The story of how is the most important part of this post, so we're putting it before the data.
Our first agent-authoring classifier matched any branch starting with a date prefix like 04-08-* on the assumption that AI agents fan out work in date-stamped batches. Unkey had 26 such branches. We initially flagged it as 100% agent-authored.
It was 0%. Every one of those 26 branches was hand-written by Unkey engineers. The date-prefix pattern is the default branch naming convention for Graphite, a CLI tool human developers use to manage stacked PRs. Six of the branches we examined formed a classic 2-hour stacked refactor by a single engineer who knew exactly how much zero-series cardinality they were eliminating. Not an agent. Not even close.
Our regex matched any branch starting with claude_ on the assumption that Claude Code branches use the claude prefix. Hatchet had a branch called claude_mcp_ts that we flagged as agent-authored.
It wasn't. The branch was 13 commits by a Hatchet engineer building an MCP server for Claude Desktop. The branch name describes the feature, not the authorship. Same class of mistake as Unkey: a feature naming convention overlapping with what we assumed was an agent signal.
We ran a manual validation pass before publishing. For each branch flagged as agent-authored, we checked the actual commit author, commit cadence, and commit message style. The Graphite stacks and the MCP feature branch fell apart immediately under inspection. We removed both rules from the classifier and recalculated.
Then we did the opposite check: for each branch we did NOT flag as agent-authored in repos where agents are known to be active, we looked at the commit author. We found 9 branches in React Email named fix/<slug>-<4hex> with no "cursor" anywhere in the name. They were all authored by [email protected]. Cursor's Background Agents feature uses semantic branch names with no agent prefix. Our regex completely missed them.
So we added a second signal: the commit author email on the branch tip, plus Co-authored-by trailers in the full branch history. A branch is now flagged as agent-authored if either the name pattern or the commit metadata indicates an agent. The corrected classifier catches what naming alone misses.
Branch names lie. Commit metadata lies less. Use both, validate manually, and disclose your limitations. That's how you publish defensible numbers.
After both corrections and the addition of the commit-author check, here's the per-repo breakdown:
| Repo | Conflicts on agent branches |
|---|---|
| React Email | 100% (245/245) |
| Inngest | 100% (594/594) |
| Trigger.dev | 17% (2/12) |
| Polar | 6% (9/148) |
| Hatchet | 0% (0/5) |
| Hoppscotch | 0% (0/120) |
| Unkey | 0% (0/37,086) |
| Drizzle ORM | 0% (0/28,903) |
Two things stand out. First, the four repos with active agent use show clean signal: every conflict in those repos sits on at least one agent-authored branch. Second, Unkey and Drizzle ORM together account for 65,989 conflicts (98% of the total) but neither has measurable agent activity. The conflicts in those repos come from human refactors that happen to be massive in scope.
This is why we exclude those two from the headline number. They're outliers driven by the scale of human refactoring, not by agentic patterns. In the remaining six repos, 850 of 1,124 conflicts (75.62%) come from agent-authored branches.
Three out of four cross-branch conflicts in normal production repos are agent-authored. As more teams adopt parallel agent workflows, that ratio is going to climb fast.
This is exactly the pattern that gets worse as agent adoption scales. When humans refactor a shared interface, they coordinate. They post in Slack. They check with the other teams who depend on that interface. They hold the merge until everyone updates. Agents don't do any of that. Agent A doesn't know Agent B exists. Agent A finishes its task, pushes its branch, and moves on. The implicit coordination layer that humans provide is missing entirely from an agentic workflow.
The pattern was overwhelmingly consistent. 73% of the conflicts were the same shape: a function gained a required parameter on one branch and a caller on another branch is still passing the old signature. Both branches pass their tests in isolation. The conflict only manifests when both branches merge into main.
The breakdown by pattern, across all 8 repos:
| Pattern | Conflicts | Share |
|---|---|---|
| Function gained required parameter | 48,830 | 72.8% |
| Function parameter renamed | 17,954 | 26.8% |
| Function removed parameter | 329 | 0.5% |
The 17,954 renamed parameter conflicts are concentrated in Drizzle ORM and Unkey. Excluding those two outliers, the remaining six normal repos show an even simpler pattern:
| Pattern | Conflicts | Share |
|---|---|---|
| Function gained required parameter | 879 | 78.2% |
| Function removed parameter | 245 | 21.8% |
The takeaway is simple: the most common way agents and humans break each other's code is by changing the shape of a function while another branch is still using the old shape. This isn't an exotic class of bug. It's the most basic form of compatibility drift, and it's invisible to every tool that exists today because every tool checks branches in isolation.
The conflicts spanned three major languages. In the normal repo set:
| Language | Share |
|---|---|
| Go | 52.9% |
| TypeScript | 33.5% |
| Python | 13.6% |
Go showing up first is the biggest surprise. The narrative around AI coding tools is that they're a JavaScript and Python problem. The data says otherwise. Backend services in Go are getting hit hardest, possibly because Go's strict typing makes signature drift more likely to surface as a real break rather than a silent runtime issue.
We use two signals to classify a branch as agent-authored:
Branch name regex. Matches branches starting with cursor/, cursor-, claude/, claude-, copilot/, copilot-, codex/, or codex-. We deliberately do NOT match underscore-separated names like claude_mcp_ts because those are feature branches, not agent branches. We learned this from the Hatchet false positive.
Commit metadata. Matches branches where the tip commit author email is [email protected], the GitHub Copilot bot, or [email protected], OR where any commit body in the branch history contains a Co-authored-by trailer for Claude or Cursor Agent, OR a claude.ai/code/session_ link. This catches Cursor Background Agents and other tools that use semantic branch names without agent prefixes.
A branch is classified as agent-authored if either signal fires. A conflict pair is classified as agent-authored if either branch in the pair is agent-authored. We always anchor our git queries at origin/<branch> rather than local refs because stale local branches can pull in unrelated commits and produce false positives.
What we miss. Centaur workflows where a human commits AI-generated code under their own git config look human to us. Internal enterprise agents that don't use any of the public naming conventions or commit signatures look human to us. The 76% number is therefore a directional minimum. The real share of conflicts caused by AI-generated code is likely higher than what we measure.
The full agent classification rules, the raw scan JSON for all 8 repos, and the per-repo timelines are public in our findings library so anyone can reproduce these counts.
Scan data is perishable. Branches merge daily. Conflicts appear and disappear as code moves through the system. We scanned the same 8 repos three times in 6 days:
| Date | Total conflicts |
|---|---|
| April 3 | 97,282 |
| April 5 | 22,622 |
| April 9 | 67,113 |
That's a swing of 75,000 conflicts in 6 days. Branches merged. New branches were created. Refactors landed. The compatibility surface of these codebases is moving constantly, and a single snapshot only tells you what was true at one moment.
This is why continuous scanning matters more than one-time audits. A single scan is a photograph. Running Rosentic on every PR is a security camera.
None of the engineering teams whose codebases we scanned are doing anything wrong. These are well-run repositories with strong CI, good code review practices, and engineers who care about quality. The conflicts exist because no tool that exists today, anywhere, looks at multiple branches together.
CI tests each branch in isolation. Code review looks at one PR at a time. Static analysis tools scan a single codebase, not the relationships between parallel branches. Git itself merges text without understanding what the code does. Every layer of the existing toolchain is blind to this category of problem.
The result is that conflicts pile up silently between active branches. When agent fan-outs happen, the count can go from zero to tens of thousands in a single day. We watched one repo go from a low count to over 37,000 in four days as a coordinated refactor rolled out across multiple packages. Nobody at the company had any way to see it happening.
That's the gap we built Rosentic to fill.
The Rosentic engine uses tree-sitter AST parsing across 11 languages to compare every active branch pair in a repository. It's fully deterministic. No LLMs in the detection loop. Same input, same output, every time. It runs as a GitHub Action that takes 60 seconds to install and reports findings directly on your PRs. Your code never leaves your runners.
The eight repos in this study are public, which is why we can write about them. We've been running scans on private repos for design partners with the same engine and seeing the same patterns. If you want to see what the engine finds on your own repository, the GitHub Action is free during early access.