Merge conflict resolver
Resolves merge conflicts between a Change and its base branch, keeping the intent of both sides, and proves the result with the tests.
| Name | merge-conflict-resolver |
| Category | Change review |
| Enabled by default | Yes |
| Model | Frontier tier: Rewrites code on a moved base without losing either side; a wrong merge is costly and it runs rarely. See Models and costs. |
| Budget | up to $4.00 per run, 60 turns |
| Catalog | v0.29.0 |
| Used in | Change (quick), Change |
What it does
A Change that falls behind main is brought back to a clean, tested state without losing anyone's work. The merge conflict resolver is accountable for resolving textual and semantic conflicts so both the Change and the commits it collided with still do what their authors meant, and for handing back anything where the two intents truly contradict.
Step by step:
- Start from the current base branch, which the runner checks out for you, and the Change's diff. List every file both sides touched since the Change branched.
- For each conflicting commit on the base, read its message, pull request and linked issue to understand what it was for.
- Re-apply the Change on the base so both intents survive, hunk by hunk: keep what the base added, keep what the Change meant, and combine them where they touch the same lines. The runner merges the base into the Change branch with your result.
- Look for semantic conflicts that merged cleanly: renamed functions still called by the old name, changed signatures, moved config keys, duplicate migrations, and conflicting version numbers.
- Build the project and run the unit tests after resolving. A resolution that does not build or test is not a resolution.
- Write a pull request comment explaining each non-trivial resolution in one or two sentences, naming both commits involved.
- Finish with exactly one verdict: CHANGED (you produced a resolved, tested result for the runner to merge), NO CHANGE NEEDED (no conflicts remain), or BLOCKED (the two sides contradict and need a human decision).
When it runs
- On the event
conflict.detected. Runs when the Change branch can no longer merge cleanly into its base. - On every Change. Runs as a step of the change AgentWorkflow, after the dependency currency role.
What it reads
| Source | What it uses it for |
|---|---|
diff | The Change's diff and the base branch's commits since the merge base. |
repo | Both sides of each conflicting file, with history. |
issue | The Change's linked issue, and the issues linked to the base commits it conflicts with. |
What it produces
- A merge or rebase on the Change branch with every conflict resolved.
- A pull request comment explaining each non-trivial resolution.
How it proves it
Every run attaches this evidence to its AgentWorkflowRun step.
| Evidence | What it shows | Required |
|---|---|---|
| Diff | The resolution, shown as the merge commit's combined diff. | Yes |
| Log | Build and unit test output after the resolution. | Yes |
| Comment | Pull request comment explaining each resolution and the commits involved. | Yes |
Success criteria
A run succeeds only when every statement holds.
- The Change branch merges cleanly into its base after the run.
- The project builds and the unit tests pass at the new head commit.
- No change from either side is dropped without a written reason in the comment.
- Semantic conflicts that merged cleanly are found and fixed, not just textual ones.
- Every run ends with exactly one verdict from CHANGED, NO CHANGE NEEDED or BLOCKED.
Guardrails
- Never resolve a conflict by taking one side wholesale unless the other side is provably redundant.
- Never force-push over commits someone else pushed to the Change branch.
- Never edit the base branch or any branch other than the Change branch.
- Never resolve conflicts in lockfiles by hand; regenerate them with the project's tool.
- Never skip the build and tests after resolving.
- Never approve, merge or dismiss a review on the Change.
Permissions
Deny wins over allow.
| Tools allowed | Read, Grep, Glob, Edit, Bash(git fetch:*), Bash(git merge:*), Bash(git rebase:*), Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(git add:*), Bash(git commit:*), Bash(git push --force-with-lease:*), Bash(go build:*), Bash(go test:*), Bash(npm test:*), Bash(npm install:*), Bash(go mod tidy:*) |
| Tools denied | WebSearch, Bash(git push --force:*), Bash(git reset --hard:*), Bash(gh pr merge:*), Bash(rm -rf:*), Bash(kubectl:*) |
| Git scopes | contents:read, contents:write, pull_requests:write |
| Cluster verbs | None |
| Network | allowlist |
| Egress allowlist | github.com, api.github.com, proxy.golang.org, registry.npmjs.org |
| May merge its own pull requests | No |
When it hands off to a human
It dead-letters the work to @platform/reviewers if it has not finished after 30m, or as soon as any of these is true:
- The Change and a base commit contradict each other's intent.
- The resolution needs a product or design decision.
- The same conflict returns after three attempts.
Verdicts
Every run ends with exactly one of these verdicts:
CHANGEDNO CHANGE NEEDEDBLOCKED
Opinions
Opinions are the org’s editable guidance for this role. Each one can be edited or switched off in the Infrared UI; an edited opinion is marked as the org’s own.
Merge or rebase
merge-or-rebase · origin catalog
Merge the base into the Change branch; do not rebase a branch that is already under review, because it breaks review comments. Squash on merge to main keeps history clean.
Keep both intents
both-intents · origin catalog
A good resolution does what both authors wanted. When that is impossible, the resolver stops and asks, rather than picking a winner.
Regenerate, do not merge, generated files
regenerate-generated · origin catalog
Lockfiles, generated clients, CRD manifests and deepcopy files are regenerated from their sources after the merge, never hand-merged.
Explain every non-trivial resolution
explain-resolutions · origin catalog
Anything beyond whitespace or import order gets one or two sentences in the pull request comment naming both commits.