PRODUCTS

KEYWORDS

Conflicts In The Wild

I got a question last week asking about conflict resolution. The user had read Programmatic Data Conflict Resolution and Three-Way Merge in a SQL Database and was left wanting more. Both posts use the same line:

Resolving conflicts is up to the user.

The user wanted to know what users actually do. This article is my answer.

What is a Conflict?#

A data conflict happens when Dolt’s three-way merge can’t auto-resolve. The same row, column pair was modified on both branches since they last shared an ancestor and Dolt doesn’t know which version should win. Dolt surfaces the conflict in the dolt_conflicts_$table system table with three versions of the row: base, ours, and theirs. From there, you decide what to do. You can resolve manually, with stored procedures, or with programmatic resolution logic.

Dolt also surfaces schema conflicts. The conflict detection rules are complicated and even rarer that data conflicts. Schema conflicts generally will be manually resolved and thus, we’re going to ignore them in this article to focus on data conflicts.

Most Conflicts Never Happen#

Before explaining the conflict resolution patterns, the boring truth. Most of our users experience conflicts very rarely. Engineers design their systems so conflicts don’t happen. Schema is partitioned by writer. Branches are short-lived. Single writer per row. autoincrement counters are shared between branches. A conflict is an exception, not a common case.

This matters because elaborate business logic to resolve a conflict is real but rare. This is the truth behind “resolving conflicts is up to the user”. Some users run Dolt in production for years and hit a conflict a handful of times. Most users treat conflict resolution like exception handling: have a plan, but optimize the happy path.

For the human editing data case on DoltHub, conflicts get resolved through the DoltHub user interface. This is the same flow as a merge conflict on GitHub. A human looks, decides, and clicks. This article isn’t about that case.

This article is about the automated case. Your application hits a conflict in the middle of the night. What happens? In these cases we see three common patterns:

  1. Bail
  2. Note and Continue
  3. Resolve

1. Bail#

Oops. That’s a conflict. Something bad happened. Rebase from main, redrive my change off the latest, try again.

This is by far the most common approach. The application catches the conflict, rolls back, pulls tip, and reapplies its change against fresh data. The equivalent of “Oh shit, I didn’t realize I was working off an old commit. I need to grab tip and redo my changes.” Optimistic concurrency, but with branches. You are relying on existing application logic to handle the conflicting write on the second pass.

The difference between this approach and optimistic concurrency is you can leave the conflicting branch around and debug the conflict later. The data is not destroyed. Put a conflict error in the logs and pick the issue up when you’re ready. Wait for a handful of conflicts to occur so you can see some patterns. Leverage the power of version control to make your application more durable against conflicting writes.

2. Note Conflict and Continue#

Some users don’t bail. They commit one side of the merge in the moment, usually “ours”, and let the conflict sit in dolt_conflicts_$table as a record that something weird happened. This is not the default Dolt option. You must enable this workflow with the system variable @@dolt_allow_commit_conflicts.

Then, a nightly-ish post process comes around and decides what to do. Maybe it picks the other side. Maybe it makes an issue for a human. Maybe it just logs the divergence and moves on. This is the formal method for the “leave an unmerged branch with conflicts” strategy above. You can embed complicated business rules for conflicts here, including escalating to a human if necessary.

I think of this as “offline conflict resolution”. The conflict is a signal, not a blocker. The transaction succeeded with one side picked, similar to a traditional transaction rollback that you can still inspect later. The history has a complete record of what diverged. Cleanup happens out of band.

This pattern works when moving forward in the moment matters more than perfect data, when you have enough conflicts that batching pays off, or when you have a review process that can run async.

3. Resolve#

Finally, you can write code to fix the conflict at merge time. You write business logic that decides what to do with the conflicting merge. Query dolt_conflicts_$table, look at the base, ours, and theirs, and pick. Maybe newest timestamp wins. Maybe you sum the diffs. Maybe you ask the user.

This is the least popular approach I see in the wild.

The reason is most users haven’t had to build this kind of business logic before. Their previous systems didn’t surface conflicts. With Dolt, they suddenly have visibility into a class of problem they used to silently lose data on. The first instinct is “keep the history, don’t try to be too clever”. They reach for #1 or #2.

So, you can run #1 or #2 for a while, start to see patterns and build business logic to resolve certain classes of conflict correctly in the moment. This is how you get to #3.

Do Agents Help?#

The same user also had two more pointed questions about agents and conflicts:

  1. Are agents resolving conflicts now?
  2. How do we handle probabilistic agents playing judge?

Honestly, I haven’t seen anyone build this yet. It’s only been a few months of agents writing code and most people aren’t even dreaming of agents writing to databases, because traditional databases are not version controlled. But I think it’s coming to Dolt soon.

The argument is simple. A conflict is a three-row decision: base, ours, theirs. An agent with context about your business can almost certainly make a better call than a hardcoded “take the most recent timestamp” rule.

If I were building this today, I would do the following.

  1. Have the agent propose a resolution into a staging table, not the live row.
  2. Have the agent justify the proposal in plain English in the same commit.
  3. Have a human or a higher-trust reviewer agent merge the proposal before it goes live.
  4. Keep the entire chain — conflict, proposal, justification, approval — in commit history.

If you later find out the agent picked wrong, dolt revert and try again with more context.

So, agents resolving conflicts may be coming to a database near you really soon.

Conclusion#

Users use three strategies to manage conflicts in Dolt: bail, note and continue, and resolve. This is a new area that generally requires innovation. Agents might help this process in the future, but not yet. Questions about conflicts? Come by our Discord and I’ll be happy to answer.