FA-076 / Distributed coordination / Open access
Read repair resurrects a deleted record · case 01
A surviving old value wins because the merge removes deletion markers before comparing versions.
ROOT CAUSE
A tombstone is treated as absence rather than a versioned state transition.
VERIFIED REPAIR
Choose the greatest version across values and tombstones, preferring deletion on an equal-version conflict.
Unsuccessful approach: Making any tombstone permanently dominant also discards legitimate later recreations.
Case contract
Records are [version,kind,value] with kind put or delete. Return the latest value or None when the latest record is a deletion; deletion wins an equal-version put/delete tie. Equal-version put values are assumed identical; the model has no wall-clock conflict resolution.
Why this case matters
Models anti-entropy repair between replicas retaining different parts of a delete/recreate history.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(records):
live = [r for r in records if r[1] == 'put']
return max(live, key=lambda r: r[0])[2] if live else None
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('new delete suppresses stale put', solve([[N, 'put', 'old'], [N+1, 'delete', None]]), None)
check('later recreation', solve([[N, 'delete', None], [N+1, 'put', 'new']]), 'new')
check('delete wins version tie', solve([[N, 'put', 'old'], [N, 'delete', None]]), None)
check('tie independent of arrival', solve([[N, 'delete', None], [N, 'put', 'old']]), None)
check('newer of two live values', solve([[N, 'put', 'old'], [N+2, 'put', 'new']]), 'new')
check('empty replicas', solve([]), None)
check('only tombstone', solve([[N, 'delete', None]]), None)
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 |
|---|---|---|---|
| new delete suppresses stale put | old | None | Failed |
| later recreation | new | new | Passed |
| delete wins version tie | old | None | Failed |
| tie independent of arrival | old | None | Failed |
| newer of two live values | new | new | Passed |
| empty replicas | None | None | Passed |
| only tombstone | None | None | Passed |
SHA-256 / 6215124347f360e6afeccddaf115baa03285ad3db7d4fcf6ef24e7f7942fd92f
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(records):
if any(r[1] == 'delete' for r in records):
return None
return max(records, key=lambda r: r[0])[2] if records else None
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('new delete suppresses stale put', solve([[N, 'put', 'old'], [N+1, 'delete', None]]), None)
check('later recreation', solve([[N, 'delete', None], [N+1, 'put', 'new']]), 'new')
check('delete wins version tie', solve([[N, 'put', 'old'], [N, 'delete', None]]), None)
check('tie independent of arrival', solve([[N, 'delete', None], [N, 'put', 'old']]), None)
check('newer of two live values', solve([[N, 'put', 'old'], [N+2, 'put', 'new']]), 'new')
check('empty replicas', solve([]), None)
check('only tombstone', solve([[N, 'delete', None]]), None)
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 |
|---|---|---|---|
| new delete suppresses stale put | None | None | Passed |
| later recreation | None | new | Failed |
| delete wins version tie | None | None | Passed |
| tie independent of arrival | None | None | Passed |
| newer of two live values | new | new | Passed |
| empty replicas | None | None | Passed |
| only tombstone | None | None | Passed |
SHA-256 / be9b211bb506d50d0a12b0ec0fb16a67c618e364511d8828d34fc7adade5f5c9
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(records):
if not records:
return None
latest = max(records, key=lambda r: (r[0], r[1] == 'delete'))
return latest[2] if latest[1] == 'put' else None
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('new delete suppresses stale put', solve([[N, 'put', 'old'], [N+1, 'delete', None]]), None)
check('later recreation', solve([[N, 'delete', None], [N+1, 'put', 'new']]), 'new')
check('delete wins version tie', solve([[N, 'put', 'old'], [N, 'delete', None]]), None)
check('tie independent of arrival', solve([[N, 'delete', None], [N, 'put', 'old']]), None)
check('newer of two live values', solve([[N, 'put', 'old'], [N+2, 'put', 'new']]), 'new')
check('empty replicas', solve([]), None)
check('only tombstone', solve([[N, 'delete', None]]), None)
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 |
|---|---|---|---|
| new delete suppresses stale put | None | None | Passed |
| later recreation | new | new | Passed |
| delete wins version tie | None | None | Passed |
| tie independent of arrival | None | None | Passed |
| newer of two live values | new | new | Passed |
| empty replicas | None | None | Passed |
| only tombstone | None | None | Passed |
SHA-256 / f077d7ac121357388304a537375a2226fc373e93513953894cc7605cdc117674
Verification & scope
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:36:50.419225+00:00.
Case digest / 88aa78c61a37e369d20aa160fa77c631a86852117a06892198877921662b79ef