Merge concurrent AtlasMart states with domain-aware three-way rules, field versions, audit evidence, and explicit human escalation for irreconcilable conflicts.
Application-Level Merge: Domain Rules, Versions, and Human Resolution
When both edits matter, the application needs more than a timestamp. This lesson merges independent fields, rejects unsafe generic rules, and treats human resolution as a first-class recovery mechanism.
Design application-level conflict resolution from domain invariants rather than timestamp order.
Use base versions and field-level change sets to merge independent edits while preserving auditability.
Recognize non-commutative operations and stale-base conflicts that require explicit sequencing or compensation.
Surface irreconcilable conflicts to a human or business workflow instead of inventing a false automatic winner.
1. When both edits matter, the resolver needs domain knowledge
AtlasMart receives two offline profile edits derived from version 10. West changes the customer's phone number; east changes marketing consent. Those changes touch independent fields and can be merged safely if the application knows their meaning. In contrast, if both replicas replace the same shipping address with different values, combining the strings is nonsense. The correct action may be to ask the customer which address is authoritative.
Application-level merge means resolution logic understands the structure and invariant of the business object. It may use field-level versions, operation histories, base versions, or a human review queue. This is more work than LWW, but it preserves information instead of blindly discarding it.
2. Three-way merge starts with the common base
A useful pattern is to compare base, west, and east. If a field changed on only one branch, keep that branch's value. If both branches changed the field to the same value, keep it. If both changed the same field differently, raise a conflict unless the domain supplies a safe merge rule.
| Field | Base v10 | West v11 | East v11 | Resolution |
|---|---|---|---|---|
| phone | 111 | 222 | 111 | take west: only west changed |
| marketing_opt_in | false | false | true | take east: only east changed |
| shipping_address | Old Street 1 | West Road 9 | East Ave 4 | conflict: both changed differently |
| account_id | cust-7 | cust-7 | cust-7 | unchanged identity |
Recording the common base matters. Without it, seeing two different values does not tell you which branch changed which field or whether one branch is stale.
3. Merge rules can be non-commutative
Some operations cannot be reordered freely. “Apply a 10%
discount” and “subtract a fixed coupon” produce different
results depending on order. Inventory decrement and cancellation
may require a defined state machine. Human-edited documents can
have overlapping text changes. If
merge(A,B) differs from merge(B,A),
then replicas applying changes in different orders can diverge
unless the system first establishes order or the merge records
enough structure to make the result deterministic.
Auditability is therefore part of correctness. Store source replica/user, base version, operation identity, resolver version, and the reason a conflict was auto-merged or escalated.
4. AtlasMart lab: merge what is safe, surface what is not
Python 3.13+ standard library only. The generated lab was verified with Python 3.13.5. No database server, Docker, cloud account, paid feature, credential, firewall change, clock manipulation, process killing, or destructive failure injection is required. All conflicts, partitions, retries, and failures are deterministic in-memory simulations.
The lab performs a three-way merge of independent profile fields, creates an explicit conflict object for two shipping-address replacements, demonstrates order-sensitive business transformations, and prints an audit trail.
from copy import deepcopy
base = {
"version": 10,
"phone": "111",
"marketing_opt_in": False,
"shipping_address": "Old Street 1",
}
west = deepcopy(base)
east = deepcopy(base)
west.update(phone="222", version=11)
east.update(marketing_opt_in=True, version=11)
print("BASE:", base)
print("WEST:", west)
print("EAST:", east)
print("\nFIELD-AWARE MERGE FOR INDEPENDENT FIELDS")
merged = deepcopy(base)
merged["phone"] = west["phone"]
merged["marketing_opt_in"] = east["marketing_opt_in"]
merged["version"] = 12
print("merged:", merged)
print("\nIRRECONCILABLE SAME-FIELD CONFLICT")
west2 = deepcopy(base); west2.update(shipping_address="West Road 9", version=11)
east2 = deepcopy(base); east2.update(shipping_address="East Ave 4", version=11)
conflict = {
"field": "shipping_address",
"base": base["shipping_address"],
"west": west2["shipping_address"],
"east": east2["shipping_address"],
"status": "NEEDS_REVIEW",
}
print("conflict record:", conflict)
print("automatic winner invented?", False)
print("\nNON-COMMUTATIVE RULE WARNING")
def apply_discount_then_tax(price): return round(price * 0.90 * 1.20, 2)
def apply_tax_then_fixed_coupon(price): return round(price * 1.20 - 10, 2)
price = 100
print("discount 10% then tax 20%:", apply_discount_then_tax(price))
print("tax 20% then fixed coupon 10:", apply_tax_then_fixed_coupon(price))
print("merge rules need an explicit domain order when operations do not commute")
print("\nAUDIT TRAIL")
audit = [
{"source": "west", "base_version": 10, "changed": ["phone"]},
{"source": "east", "base_version": 10, "changed": ["marketing_opt_in"]},
{"source": "system", "result_version": 12, "rule": "merge disjoint fields"},
]
for row in audit: print(row)
The phone and marketing-consent changes both survive. The two
address updates become a NEEDS_REVIEW record
instead of a fabricated winner. The arithmetic examples show
that business transformations may be order-sensitive, so a
generic “merge both operations” rule is unsafe.
5. Human resolution is a valid distributed-systems mechanism
For high-value ambiguous conflicts, a durable review workflow can be safer than automation. A reviewer should see the base, both candidate values, who/what produced them, timestamps as supporting evidence rather than truth, and downstream effects that would follow each choice. The resolution itself should create a new authoritative version so stale clients cannot later overwrite it.
Security and privacy constrain the review surface: a conflict UI must not expose another tenant's data, and sensitive historical values may need redaction or retention controls. “Keep every version forever” is not automatically compliant.
6. Deliberately wrong approach: merge every collection by union
Set union preserves concurrent additions, but many collections encode removals, uniqueness, ordering, or quantities. Unioning two shopping carts can resurrect a removed item. Summing two absolute inventory counts double-counts shared base stock. Concatenating permission sets can re-grant revoked access. Generic collection algebra must not replace the domain invariant.
7. Production judgment and bridge
Use application merge when conflicts are meaningful but resolvable from domain structure. Keep resolver code versioned and test it with commutativity/order permutations, stale bases, repeated delivery, deletes, schema evolution, and malformed input. Observe conflict frequency by field/type, automatic-merge success rate, human-review backlog, age of unresolved conflicts, repeated-resolution rate, and downstream reconciliation errors.
If a data type can be designed so all replicas merge independently and deterministically without a central conflict resolver, a Conflict-Free Replicated Data Type (CRDT) may be appropriate. The next lesson studies the algebra that makes that possible—and the limits of the claim.
Check your understanding
- Why is a common base useful in application merge?
- When should the application surface a conflict instead of choosing automatically?
- Why do non-commutative operations matter?
- Why is set union not a universal collection merge?
- What should an audit record capture?
Review the answers
1. It distinguishes fields changed on one branch from fields changed on both, enabling safe three-way merge decisions.
2. When concurrent changes affect the same semantic fact and no domain-safe deterministic merge exists.
3. Different application orders can produce different results, so replicas need explicit ordering or a merge design that removes that ambiguity.
4. It cannot correctly represent removals, quantities, ordering, revocations, or other domain-specific semantics.
5. Base/version context, source/writer, operation identity, changed fields/operations, resolver rule/version, and final decision or escalation.
References
Foundational claims use primary research/specifications where practical. Product documentation is used only as a current implementation example and is not required for the mandatory labs.
- DeCandia et al. — Dynamo — Primary system example of application-assisted semantic reconciliation.
- Saito & Shapiro — Optimistic Replication — Conflict detection and reconciliation foundations for optimistic replicated systems.
- RFC 6902 — JSON Patch — Standards-track operation representation useful for reasoning about explicit field/document mutations; not itself a concurrency protocol.
- RFC 7396 — JSON Merge Patch — Standards-track merge-patch format; useful contrast with domain-aware conflict resolution.