FA-75666 / Text diff and three-way merge / Open access
Three-way key-value merge: a deletion silently beats a concurrent modification · case 01
A key modified on our branch and deleted on theirs disappears without a conflict.
ROOT CAUSE
A special case resolves delete-versus-modify in favour of the deletion.
VERIFIED REPAIR
Treat a deletion on one side and a modification on the other as a conflict.
Unsuccessful approach: Letting the modification win still hides the conflict from the user.
Case contract
Merge base, ours and theirs maps key by key over the union of keys; an absent key and a key holding null are different states. If ours and theirs agree, take that state; else if ours equals base take theirs; else if theirs equals base take ours; otherwise record a conflict and keep ours. Return sorted merged [key, value] pairs and sorted conflicting keys.
Why this case matters
Structured configuration and lock files are merged per key, where deletions and null values must stay distinguishable.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(base, ours, theirs):
MISSING = object()
merged, conflicts = {}, []
for k in sorted(set(base) | set(ours) | set(theirs)):
b = base.get(k, MISSING)
o = ours.get(k, MISSING)
t = theirs.get(k, MISSING)
if o == t:
r = o
elif o == b:
r = t
elif t == b:
r = o
elif t is MISSING:
r = t
else:
conflicts.append(k)
r = o
if r is not MISSING:
merged[k] = r
return {'merged': sorted([k, v] for k, v in merged.items()), 'conflicts': conflicts}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '81', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z1'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e1'}], {'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm1'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
2: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '82', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '82']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z2'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z2'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e2'}], {'merged': [['extra', 'e2'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm2'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm2'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
3: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '83', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '83']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z3'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z3'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e3'}], {'merged': [['extra', 'e3'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm3'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm3'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
4: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '84', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '84']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z4'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z4'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e4'}], {'merged': [['extra', 'e4'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm4'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm4'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
5: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '85', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '85']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z5'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z5'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e5'}], {'merged': [['extra', 'e5'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm5'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm5'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| each side changes a different key | {'conflicts': [], 'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']]} | {'conflicts': [], 'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']]} | Passed |
| both change a key the same way | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']]} | Passed |
| both delete the same key | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | Passed |
| conflicting changes keep ours | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']]} | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']]} | Passed |
| delete versus modify conflicts | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | {'conflicts': ['mode'], 'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']]} | Failed |
| explicit null differs from deletion | {'conflicts': [], 'merged': [['host', 'a'], ['mode', None], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mode', None], ['port', '80']]} | Passed |
| key added only by theirs | {'conflicts': [], 'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']]} | {'conflicts': [], 'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']]} | Passed |
| key added only by ours | {'conflicts': [], 'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']]} | Passed |
| modify versus delete conflicts | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x']]} | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x']]} | Passed |
| null in base and deleted by ours | {'conflicts': [], 'merged': [['j', '2']]} | {'conflicts': [], 'merged': [['j', '2']]} | Passed |
SHA-256 / d64af98faa6c363dfdfaf12fd9e62b323ef86507c6f47ce2a6a9d0f530f9541b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(base, ours, theirs):
MISSING = object()
merged, conflicts = {}, []
for k in sorted(set(base) | set(ours) | set(theirs)):
b = base.get(k, MISSING)
o = ours.get(k, MISSING)
t = theirs.get(k, MISSING)
if o == t:
r = o
elif o == b:
r = t
elif t == b:
r = o
elif t is MISSING or o is MISSING:
r = o if o is not MISSING else t
else:
conflicts.append(k)
r = o
if r is not MISSING:
merged[k] = r
return {'merged': sorted([k, v] for k, v in merged.items()), 'conflicts': conflicts}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '81', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z1'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e1'}], {'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm1'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
2: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '82', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '82']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z2'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z2'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e2'}], {'merged': [['extra', 'e2'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm2'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm2'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
3: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '83', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '83']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z3'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z3'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e3'}], {'merged': [['extra', 'e3'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm3'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm3'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
4: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '84', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '84']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z4'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z4'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e4'}], {'merged': [['extra', 'e4'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm4'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm4'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
5: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '85', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '85']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z5'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z5'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e5'}], {'merged': [['extra', 'e5'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm5'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm5'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| each side changes a different key | {'conflicts': [], 'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']]} | {'conflicts': [], 'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']]} | Passed |
| both change a key the same way | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']]} | Passed |
| both delete the same key | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | Passed |
| conflicting changes keep ours | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']]} | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']]} | Passed |
| delete versus modify conflicts | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']]} | {'conflicts': ['mode'], 'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']]} | Failed |
| explicit null differs from deletion | {'conflicts': [], 'merged': [['host', 'a'], ['mode', None], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mode', None], ['port', '80']]} | Passed |
| key added only by theirs | {'conflicts': [], 'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']]} | {'conflicts': [], 'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']]} | Passed |
| key added only by ours | {'conflicts': [], 'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']]} | Passed |
| modify versus delete conflicts | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '443']]} | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x']]} | Failed |
| null in base and deleted by ours | {'conflicts': [], 'merged': [['j', '2']]} | {'conflicts': [], 'merged': [['j', '2']]} | Passed |
SHA-256 / 8091a3dceccd655e6c45b9611a28e721a92aa1bc1b65c0ca8187cf0a5932dba5
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(base, ours, theirs):
MISSING = object()
merged, conflicts = {}, []
for k in sorted(set(base) | set(ours) | set(theirs)):
b = base.get(k, MISSING)
o = ours.get(k, MISSING)
t = theirs.get(k, MISSING)
if o == t:
r = o
elif o == b:
r = t
elif t == b:
r = o
else:
conflicts.append(k)
r = o
if r is not MISSING:
merged[k] = r
return {'merged': sorted([k, v] for k, v in merged.items()), 'conflicts': conflicts}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
cases = {
1: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '81', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z1'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e1'}], {'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm1'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
2: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '82', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '82']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z2'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z2'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e2'}], {'merged': [['extra', 'e2'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm2'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm2'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
3: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '83', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '83']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z3'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z3'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e3'}], {'merged': [['extra', 'e3'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm3'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm3'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
4: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '84', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '84']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z4'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z4'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e4'}], {'merged': [['extra', 'e4'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm4'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm4'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
5: [('each side changes a different key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'b', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '85', 'mode': 'x'}], {'merged': [['host', 'b'], ['mode', 'x'], ['port', '85']], 'conflicts': []}), ('both change a key the same way', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'y'}, {'host': 'a', 'port': '80', 'mode': 'y'}], {'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']], 'conflicts': []}), ('both delete the same key', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['port', '80']], 'conflicts': []}), ('conflicting changes keep ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '1', 'mode': 'x'}, {'host': 'a', 'port': '2', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']], 'conflicts': ['port']}), ('delete versus modify conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'z5'}, {'host': 'a', 'port': '80'}], {'merged': [['host', 'a'], ['mode', 'z5'], ['port', '80']], 'conflicts': ['mode']}), ('explicit null differs from deletion', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': None}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', None], ['port', '80']], 'conflicts': []}), ('key added only by theirs', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'extra': 'e5'}], {'merged': [['extra', 'e5'], ['host', 'a'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('key added only by ours', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'port': '80', 'mode': 'x', 'mine': 'm5'}, {'host': 'a', 'port': '80', 'mode': 'x'}], {'merged': [['host', 'a'], ['mine', 'm5'], ['mode', 'x'], ['port', '80']], 'conflicts': []}), ('modify versus delete conflicts', [{'host': 'a', 'port': '80', 'mode': 'x'}, {'host': 'a', 'mode': 'x'}, {'host': 'a', 'port': '443', 'mode': 'x'}], {'merged': [['host', 'a'], ['mode', 'x']], 'conflicts': ['port']}), ('null in base and deleted by ours', [{'k': None, 'j': '1'}, {'j': '1'}, {'k': None, 'j': '2'}], {'merged': [['j', '2']], 'conflicts': []})],
}[N]
for label, args, expected in cases:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| each side changes a different key | {'conflicts': [], 'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']]} | {'conflicts': [], 'merged': [['host', 'b'], ['mode', 'x'], ['port', '81']]} | Passed |
| both change a key the same way | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mode', 'y'], ['port', '80']]} | Passed |
| both delete the same key | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['port', '80']]} | Passed |
| conflicting changes keep ours | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']]} | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x'], ['port', '1']]} | Passed |
| delete versus modify conflicts | {'conflicts': ['mode'], 'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']]} | {'conflicts': ['mode'], 'merged': [['host', 'a'], ['mode', 'z1'], ['port', '80']]} | Passed |
| explicit null differs from deletion | {'conflicts': [], 'merged': [['host', 'a'], ['mode', None], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mode', None], ['port', '80']]} | Passed |
| key added only by theirs | {'conflicts': [], 'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']]} | {'conflicts': [], 'merged': [['extra', 'e1'], ['host', 'a'], ['mode', 'x'], ['port', '80']]} | Passed |
| key added only by ours | {'conflicts': [], 'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']]} | {'conflicts': [], 'merged': [['host', 'a'], ['mine', 'm1'], ['mode', 'x'], ['port', '80']]} | Passed |
| modify versus delete conflicts | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x']]} | {'conflicts': ['port'], 'merged': [['host', 'a'], ['mode', 'x']]} | Passed |
| null in base and deleted by ours | {'conflicts': [], 'merged': [['j', '2']]} | {'conflicts': [], 'merged': [['j', '2']]} | Passed |
SHA-256 / 8d90e3af1313999b155a9ede11ce8e2147e1a6712b46c8e934df371b31dd4764
Verification & scope
A deterministic, bounded teaching model of one diff, patch or merge rule with stipulated conventions; it is not a production diff or version-control implementation and makes no claim of conformance to any specific tool. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:49:09.027215+00:00.
Case digest / 9420a65573e36c524e04ae3a4aef8b7e2a67f80556022e2078915168732097f9