FA-30251 / HTTP retries / Open access
Conditional mutation retry reconciliation: Inspection gate violates retry transition semantics · case 01
Inspection gate violates retry transition semantics
ROOT CAUSE
Inspection gate violates retry transition semantics
VERIFIED REPAIR
Restore the specified transition if state!='uncertain':.
Unsuccessful approach: The attempted repair changes the faulty site to if state=='ready': but still violates a regression oracle.
Case contract
begin(version,desired) creates a pending conditional write. sent records that it may have reached the server; lost means response absent. inspect(version,value) after loss reconciles: desired value at version+1 is committed, unchanged original version permits retry, any other state conflicts. retry only from retry state retains original precondition and desired body. ack(value) succeeds only for an active sent request. Return decisions and outgoing retry preconditions.
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):
version=0; desired=None; state='idle'; out=[]
for e in events:
if e[0]=='begin':
version=e[1]; desired=e[2]; state='ready'
elif e[0]=='sent':
if state=='ready': state='sent'
elif e[0]=='lost':
if state=='sent': state='uncertain'
elif e[0]=='inspect':
if state=='idle': out.append('ignored'); continue
if e[1]==version+1 and e[2]==desired:
state='done'; out.append('committed')
elif e[1]==version:
state='retry'; out.append('retryable')
else: state='conflict'; out.append('conflict')
elif e[0]=='retry':
if state!='retry': out.append('denied'); continue
out.append(['send',version,desired]); state='ready'
elif e[0]=='ack':
if state=='sent': state='done'; out.append(['success',e[1]])
else: out.append('ignored')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('0', solve([]), [])
check('1', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N,N+1),('retry',),('retry',),('sent',),('ack',N+9)]), ['retryable',['send',N,N+9],'denied',['success',N+9]])
check('2', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+1,N+9),('retry',),('inspect',N,N)]), ['committed','denied','ignored'])
check('3', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+1,N+8),('retry',),('inspect',N,N)]), ['conflict','denied','ignored'])
check('4', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+2,N+9),('retry',)]), ['conflict','denied'])
check('5', solve([('begin',N,N+9),('lost',),('inspect',N,N),('ack',N)]), ['ignored','ignored'])
check('6', solve([('begin',N,N+9),('sent',),('lost',),('ack',N),('inspect',N-1,N),('retry',)]), ['ignored','conflict','denied'])
check('7', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N,N),('retry',),('ack',N)]), ['retryable',['send',N,N+9],'ignored'])
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 | ['retryable', ['send', 1, 10], 'denied', ['success', 10]] | ['retryable', ['send', 1, 10], 'denied', ['success', 10]] | Passed |
| 2 | ['committed', 'denied', 'retryable'] | ['committed', 'denied', 'ignored'] | Failed |
| 3 | ['conflict', 'denied', 'retryable'] | ['conflict', 'denied', 'ignored'] | Failed |
| 4 | ['conflict', 'denied'] | ['conflict', 'denied'] | Passed |
| 5 | ['retryable', 'ignored'] | ['ignored', 'ignored'] | Failed |
| 6 | ['ignored', 'conflict', 'denied'] | ['ignored', 'conflict', 'denied'] | Passed |
| 7 | ['retryable', ['send', 1, 10], 'ignored'] | ['retryable', ['send', 1, 10], 'ignored'] | Passed |
SHA-256 / 4dfe5078c191e96921c1cd854ef454608cd5bed00cc4cd65d9dad65ee9c87c6e
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
version=0; desired=None; state='idle'; out=[]
for e in events:
if e[0]=='begin':
version=e[1]; desired=e[2]; state='ready'
elif e[0]=='sent':
if state=='ready': state='sent'
elif e[0]=='lost':
if state=='sent': state='uncertain'
elif e[0]=='inspect':
if state=='ready': out.append('ignored'); continue
if e[1]==version+1 and e[2]==desired:
state='done'; out.append('committed')
elif e[1]==version:
state='retry'; out.append('retryable')
else: state='conflict'; out.append('conflict')
elif e[0]=='retry':
if state!='retry': out.append('denied'); continue
out.append(['send',version,desired]); state='ready'
elif e[0]=='ack':
if state=='sent': state='done'; out.append(['success',e[1]])
else: out.append('ignored')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('0', solve([]), [])
check('1', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N,N+1),('retry',),('retry',),('sent',),('ack',N+9)]), ['retryable',['send',N,N+9],'denied',['success',N+9]])
check('2', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+1,N+9),('retry',),('inspect',N,N)]), ['committed','denied','ignored'])
check('3', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+1,N+8),('retry',),('inspect',N,N)]), ['conflict','denied','ignored'])
check('4', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+2,N+9),('retry',)]), ['conflict','denied'])
check('5', solve([('begin',N,N+9),('lost',),('inspect',N,N),('ack',N)]), ['ignored','ignored'])
check('6', solve([('begin',N,N+9),('sent',),('lost',),('ack',N),('inspect',N-1,N),('retry',)]), ['ignored','conflict','denied'])
check('7', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N,N),('retry',),('ack',N)]), ['retryable',['send',N,N+9],'ignored'])
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 | ['retryable', ['send', 1, 10], 'denied', ['success', 10]] | ['retryable', ['send', 1, 10], 'denied', ['success', 10]] | Passed |
| 2 | ['committed', 'denied', 'retryable'] | ['committed', 'denied', 'ignored'] | Failed |
| 3 | ['conflict', 'denied', 'retryable'] | ['conflict', 'denied', 'ignored'] | Failed |
| 4 | ['conflict', 'denied'] | ['conflict', 'denied'] | Passed |
| 5 | ['ignored', 'ignored'] | ['ignored', 'ignored'] | Passed |
| 6 | ['ignored', 'conflict', 'denied'] | ['ignored', 'conflict', 'denied'] | Passed |
| 7 | ['retryable', ['send', 1, 10], 'ignored'] | ['retryable', ['send', 1, 10], 'ignored'] | Passed |
SHA-256 / 59c611c16229bcb1edb677ec1ee23fd77763bdb46131a5a4b679d1e59c4e2c7f
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(events):
version=0; desired=None; state='idle'; out=[]
for e in events:
if e[0]=='begin':
version=e[1]; desired=e[2]; state='ready'
elif e[0]=='sent':
if state=='ready': state='sent'
elif e[0]=='lost':
if state=='sent': state='uncertain'
elif e[0]=='inspect':
if state!='uncertain': out.append('ignored'); continue
if e[1]==version+1 and e[2]==desired:
state='done'; out.append('committed')
elif e[1]==version:
state='retry'; out.append('retryable')
else: state='conflict'; out.append('conflict')
elif e[0]=='retry':
if state!='retry': out.append('denied'); continue
out.append(['send',version,desired]); state='ready'
elif e[0]=='ack':
if state=='sent': state='done'; out.append(['success',e[1]])
else: out.append('ignored')
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('0', solve([]), [])
check('1', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N,N+1),('retry',),('retry',),('sent',),('ack',N+9)]), ['retryable',['send',N,N+9],'denied',['success',N+9]])
check('2', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+1,N+9),('retry',),('inspect',N,N)]), ['committed','denied','ignored'])
check('3', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+1,N+8),('retry',),('inspect',N,N)]), ['conflict','denied','ignored'])
check('4', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N+2,N+9),('retry',)]), ['conflict','denied'])
check('5', solve([('begin',N,N+9),('lost',),('inspect',N,N),('ack',N)]), ['ignored','ignored'])
check('6', solve([('begin',N,N+9),('sent',),('lost',),('ack',N),('inspect',N-1,N),('retry',)]), ['ignored','conflict','denied'])
check('7', solve([('begin',N,N+9),('sent',),('lost',),('inspect',N,N),('retry',),('ack',N)]), ['retryable',['send',N,N+9],'ignored'])
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 | ['retryable', ['send', 1, 10], 'denied', ['success', 10]] | ['retryable', ['send', 1, 10], 'denied', ['success', 10]] | Passed |
| 2 | ['committed', 'denied', 'ignored'] | ['committed', 'denied', 'ignored'] | Passed |
| 3 | ['conflict', 'denied', 'ignored'] | ['conflict', 'denied', 'ignored'] | Passed |
| 4 | ['conflict', 'denied'] | ['conflict', 'denied'] | Passed |
| 5 | ['ignored', 'ignored'] | ['ignored', 'ignored'] | Passed |
| 6 | ['ignored', 'conflict', 'denied'] | ['ignored', 'conflict', 'denied'] | Passed |
| 7 | ['retryable', ['send', 1, 10], 'ignored'] | ['retryable', ['send', 1, 10], 'ignored'] | Passed |
SHA-256 / e4da5bf408a2ab2e3676f3b11d7ca79438c4fd559672f4aad786e2abd9cefe00
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:51.135630+00:00.
Case digest / 86bc29c21b8fae076105f2fa93838b64965748113807f8633ec3499e22243b30