FA-30031 / HTTP retries / Open access
Idempotency receipt expiry during retry: Eviction state violates retry transition semantics · case 01
Eviction state violates retry transition semantics
ROOT CAUSE
Eviction state violates retry transition semantics
VERIFIED REPAIR
Restore the specified transition records.pop(k); old=None.
Unsuccessful approach: The attempted repair changes the faulty site to records.pop(k); old=[None,now,False,None] but still violates a regression oracle.
Case contract
put(key,body,expires) creates a pending receipt if no live receipt exists at current logical time. Existing live matching key returns pending or cached; mismatched body returns conflict. commit succeeds only for a live pending receipt. at(time) moves monotonic time forward. Expiry at now is expired. lookup(key) reports missing/pending/cached. Return outcomes. Commit appends committed or ignored to expose whether a durable receipt write occurred.
Why this case matters
Offline deterministic model of HTTP request retries.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
now=0; records={}; out=[]
for e in events:
if e[0]=='at': now=max(now,e[1])
elif e[0]=='put':
k,body,expires=e[1:]
old=records.get(k)
if old is not None and old[1]<=now:
records.pop(k); old=old
if old is None:
if expires<=now: out.append('expired'); continue
records[k]=[body,expires,False,None]; out.append('new')
elif old[0]!=body: out.append('conflict')
elif old[2]: out.append(['cached',old[3]])
else: out.append('pending')
elif e[0]=='commit':
old=records.get(e[1])
if old is not None and old[1]>now and not old[2]:
old[2]=True; old[3]=e[2]; out.append('committed')
else: out.append('ignored')
elif e[0]=='lookup':
old=records.get(e[1])
if old is None or old[1]<=now: out.append('missing')
elif old[2]: out.append(['cached',old[3]])
else: out.append('pending')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('0', solve([]), [])
check('1', solve([('lookup','x'),('put','a',N,3),('put','a',N,3),('commit','a',N+9),('commit','a',999),('lookup','a'),('put','a',N,3),('put','a',N+1,3)]), ['missing','new','pending','committed','ignored',['cached',N+9],['cached',N+9],'conflict'])
check('2', solve([('at',3),('put','a',N,3),('put','b',N,2)]), ['expired','expired'])
check('3', solve([('put','a',N,3),('at',3),('commit','a',99),('lookup','a'),('put','a',N+1,5),('lookup','a')]), ['new','ignored','missing','new','pending'])
check('4', solve([('at',4),('put','a',N,6),('at',6),('lookup','a')]), ['new','missing'])
check('5', solve([('put','a',N,2),('at',3),('at',1),('lookup','a')]), ['new','missing'])
check('6', solve([('commit','absent',N),('lookup','absent')]), ['ignored','missing'])
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 |
|---|---|---|---|
| 0 | [] | [] | Passed |
| 1 | ['missing', 'new', 'pending', 'committed', 'ignored', ['cached', 10], ['cached', 10], 'conflict'] | ['missing', 'new', 'pending', 'committed', 'ignored', ['cached', 10], ['cached', 10], 'conflict'] | Passed |
| 2 | ['expired', 'expired'] | ['expired', 'expired'] | Passed |
| 3 | ['new', 'ignored', 'missing', 'conflict', 'missing'] | ['new', 'ignored', 'missing', 'new', 'pending'] | Failed |
| 4 | ['new', 'missing'] | ['new', 'missing'] | Passed |
| 5 | ['new', 'missing'] | ['new', 'missing'] | Passed |
| 6 | ['ignored', 'missing'] | ['ignored', 'missing'] | Passed |
SHA-256 / 09c25b5ef4037f9ad08c80dca784365510f922613d6f68da8bb88f5046a2bf1b
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
now=0; records={}; out=[]
for e in events:
if e[0]=='at': now=max(now,e[1])
elif e[0]=='put':
k,body,expires=e[1:]
old=records.get(k)
if old is not None and old[1]<=now:
records.pop(k); old=[None,now,False,None]
if old is None:
if expires<=now: out.append('expired'); continue
records[k]=[body,expires,False,None]; out.append('new')
elif old[0]!=body: out.append('conflict')
elif old[2]: out.append(['cached',old[3]])
else: out.append('pending')
elif e[0]=='commit':
old=records.get(e[1])
if old is not None and old[1]>now and not old[2]:
old[2]=True; old[3]=e[2]; out.append('committed')
else: out.append('ignored')
elif e[0]=='lookup':
old=records.get(e[1])
if old is None or old[1]<=now: out.append('missing')
elif old[2]: out.append(['cached',old[3]])
else: out.append('pending')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('0', solve([]), [])
check('1', solve([('lookup','x'),('put','a',N,3),('put','a',N,3),('commit','a',N+9),('commit','a',999),('lookup','a'),('put','a',N,3),('put','a',N+1,3)]), ['missing','new','pending','committed','ignored',['cached',N+9],['cached',N+9],'conflict'])
check('2', solve([('at',3),('put','a',N,3),('put','b',N,2)]), ['expired','expired'])
check('3', solve([('put','a',N,3),('at',3),('commit','a',99),('lookup','a'),('put','a',N+1,5),('lookup','a')]), ['new','ignored','missing','new','pending'])
check('4', solve([('at',4),('put','a',N,6),('at',6),('lookup','a')]), ['new','missing'])
check('5', solve([('put','a',N,2),('at',3),('at',1),('lookup','a')]), ['new','missing'])
check('6', solve([('commit','absent',N),('lookup','absent')]), ['ignored','missing'])
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 |
|---|---|---|---|
| 0 | [] | [] | Passed |
| 1 | ['missing', 'new', 'pending', 'committed', 'ignored', ['cached', 10], ['cached', 10], 'conflict'] | ['missing', 'new', 'pending', 'committed', 'ignored', ['cached', 10], ['cached', 10], 'conflict'] | Passed |
| 2 | ['expired', 'expired'] | ['expired', 'expired'] | Passed |
| 3 | ['new', 'ignored', 'missing', 'conflict', 'missing'] | ['new', 'ignored', 'missing', 'new', 'pending'] | Failed |
| 4 | ['new', 'missing'] | ['new', 'missing'] | Passed |
| 5 | ['new', 'missing'] | ['new', 'missing'] | Passed |
| 6 | ['ignored', 'missing'] | ['ignored', 'missing'] | Passed |
SHA-256 / 5032d3f9c9ae82ea078d275e5378f855e645e52658f11598f6765be5fc86c89f
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
now=0; records={}; out=[]
for e in events:
if e[0]=='at': now=max(now,e[1])
elif e[0]=='put':
k,body,expires=e[1:]
old=records.get(k)
if old is not None and old[1]<=now:
records.pop(k); old=None
if old is None:
if expires<=now: out.append('expired'); continue
records[k]=[body,expires,False,None]; out.append('new')
elif old[0]!=body: out.append('conflict')
elif old[2]: out.append(['cached',old[3]])
else: out.append('pending')
elif e[0]=='commit':
old=records.get(e[1])
if old is not None and old[1]>now and not old[2]:
old[2]=True; old[3]=e[2]; out.append('committed')
else: out.append('ignored')
elif e[0]=='lookup':
old=records.get(e[1])
if old is None or old[1]<=now: out.append('missing')
elif old[2]: out.append(['cached',old[3]])
else: out.append('pending')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('0', solve([]), [])
check('1', solve([('lookup','x'),('put','a',N,3),('put','a',N,3),('commit','a',N+9),('commit','a',999),('lookup','a'),('put','a',N,3),('put','a',N+1,3)]), ['missing','new','pending','committed','ignored',['cached',N+9],['cached',N+9],'conflict'])
check('2', solve([('at',3),('put','a',N,3),('put','b',N,2)]), ['expired','expired'])
check('3', solve([('put','a',N,3),('at',3),('commit','a',99),('lookup','a'),('put','a',N+1,5),('lookup','a')]), ['new','ignored','missing','new','pending'])
check('4', solve([('at',4),('put','a',N,6),('at',6),('lookup','a')]), ['new','missing'])
check('5', solve([('put','a',N,2),('at',3),('at',1),('lookup','a')]), ['new','missing'])
check('6', solve([('commit','absent',N),('lookup','absent')]), ['ignored','missing'])
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 |
|---|---|---|---|
| 0 | [] | [] | Passed |
| 1 | ['missing', 'new', 'pending', 'committed', 'ignored', ['cached', 10], ['cached', 10], 'conflict'] | ['missing', 'new', 'pending', 'committed', 'ignored', ['cached', 10], ['cached', 10], 'conflict'] | Passed |
| 2 | ['expired', 'expired'] | ['expired', 'expired'] | Passed |
| 3 | ['new', 'ignored', 'missing', 'new', 'pending'] | ['new', 'ignored', 'missing', 'new', 'pending'] | Passed |
| 4 | ['new', 'missing'] | ['new', 'missing'] | Passed |
| 5 | ['new', 'missing'] | ['new', 'missing'] | Passed |
| 6 | ['ignored', 'missing'] | ['ignored', 'missing'] | Passed |
SHA-256 / aba0cac156c38bf6144172a6872debb1334951fa4c0faca744649e01ee90e8bb
Verification & scope
Stipulated bounded simulator, not a complete HTTP implementation or a standards conformance claim. 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:41:48.954282+00:00.
Case digest / 06ac440c7c7f9c73190edebc24d3417fde9bb8dfa7491a182e64a9b9937ccac1