FAILURE MAP
← Case archive

FA-1496 / Concurrency / Open access

Resolve a prepared participant after recovery: Prepared data becomes visible after losing its write locks · case 01

The prepared recovery operation is admitted even though prepared data becomes visible after losing its write locks.

Verified by executionVariant 1 · 9 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The admission path omits the locks retained invariant while validating the other operation preconditions.

VERIFIED REPAIR

Require set(r['locks_retained'][0]) <= set(r['locks_retained'][1]) together with every other stated precondition before accepting the operation.

Unsuccessful approach: Adding the locks retained check repairs the reported defect, but replacing the adjacent decision known check loses that independent invariant.

Case contract

Return a Boolean admission decision for resolve a prepared participant after recovery. The record r must satisfy all of: r['decision_known'] in ['commit','abort']; r['transaction_identity'][0] == r['transaction_identity'][1]; r['prepare_record'] is True; r['decision_consistent'][0] is None or r['decision_consistent'][0] == r['decision_consistent'][1]; set(r['locks_retained'][0]) <= set(r['locks_retained'][1]). Extra tracing fields are ignored; validation does not mutate the record.

Why this case matters

A deterministic local contract for concurrency. Each negative fixture violates exactly one invariant. No transport timing, persistence, cryptographic verification, or full protocol implementation is claimed.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(r):
    return (r['decision_known'] in ['commit','abort']) and (r['transaction_identity'][0] == r['transaction_identity'][1]) and (r['prepare_record'] is True) and (r['decision_consistent'][0] is None or r['decision_consistent'][0] == r['decision_consistent'][1])
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r = {'decision_known': 'commit', 'transaction_identity': ['t2', 't2'], 'prepare_record': True, 'decision_consistent': ['commit', 'commit'], 'locks_retained': [['k1'], ['k1', 'k2']]}
check('valid operation', solve(r), True)
check('An uncertain participant guesses commit without evidence', solve(dict(r, **{'decision_known': 'unknown'})), False)
check('Recovery applies another transaction decision', solve(dict(r, **{'transaction_identity': ['t1', 't2']})), False)
check('Recovery commits a transaction with no durable prepare record', solve(dict(r, **{'prepare_record': False})), False)
check('Recovery reverses a previously recorded final decision', solve(dict(r, **{'decision_consistent': ['abort', 'commit']})), False)
check('Prepared data becomes visible after losing its write locks', solve(dict(r, **{'locks_retained': [['k1'], ['k2']]})), False)
check('unrelated tracing metadata', solve(dict(r, trace='run-'+str(N))), True)
check('repeat validation is pure', solve(r), True)
invalid = {'decision_known': 'unknown', 'transaction_identity': ['t1', 't2'], 'prepare_record': False, 'decision_consistent': ['abort', 'commit'], 'locks_retained': [['k1'], ['k2']]}
keys = list(invalid)
pair = {keys[N % len(keys)]: invalid[keys[N % len(keys)]], keys[(N+1) % len(keys)]: invalid[keys[(N+1) % len(keys)]]}
check('two independent violations in variant', solve(dict(r, **pair)), False)
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 fixtureActualExpectedOutcome
valid operationTrueTruePassed
An uncertain participant guesses commit without evidenceFalseFalsePassed
Recovery applies another transaction decisionFalseFalsePassed
Recovery commits a transaction with no durable prepare recordFalseFalsePassed
Recovery reverses a previously recorded final decisionFalseFalsePassed
Prepared data becomes visible after losing its write locksTrueFalseFailed
unrelated tracing metadataTrueTruePassed
repeat validation is pureTrueTruePassed
two independent violations in variantFalseFalsePassed

SHA-256 / ba468643603fecf0db0e6473449485f99ad0ff6b485df9531f5cdc0164d4a84c

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(r):
    return (r['transaction_identity'][0] == r['transaction_identity'][1]) and (r['prepare_record'] is True) and (r['decision_consistent'][0] is None or r['decision_consistent'][0] == r['decision_consistent'][1]) and (set(r['locks_retained'][0]) <= set(r['locks_retained'][1]))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r = {'decision_known': 'commit', 'transaction_identity': ['t2', 't2'], 'prepare_record': True, 'decision_consistent': ['commit', 'commit'], 'locks_retained': [['k1'], ['k1', 'k2']]}
check('valid operation', solve(r), True)
check('An uncertain participant guesses commit without evidence', solve(dict(r, **{'decision_known': 'unknown'})), False)
check('Recovery applies another transaction decision', solve(dict(r, **{'transaction_identity': ['t1', 't2']})), False)
check('Recovery commits a transaction with no durable prepare record', solve(dict(r, **{'prepare_record': False})), False)
check('Recovery reverses a previously recorded final decision', solve(dict(r, **{'decision_consistent': ['abort', 'commit']})), False)
check('Prepared data becomes visible after losing its write locks', solve(dict(r, **{'locks_retained': [['k1'], ['k2']]})), False)
check('unrelated tracing metadata', solve(dict(r, trace='run-'+str(N))), True)
check('repeat validation is pure', solve(r), True)
invalid = {'decision_known': 'unknown', 'transaction_identity': ['t1', 't2'], 'prepare_record': False, 'decision_consistent': ['abort', 'commit'], 'locks_retained': [['k1'], ['k2']]}
keys = list(invalid)
pair = {keys[N % len(keys)]: invalid[keys[N % len(keys)]], keys[(N+1) % len(keys)]: invalid[keys[(N+1) % len(keys)]]}
check('two independent violations in variant', solve(dict(r, **pair)), False)
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 fixtureActualExpectedOutcome
valid operationTrueTruePassed
An uncertain participant guesses commit without evidenceTrueFalseFailed
Recovery applies another transaction decisionFalseFalsePassed
Recovery commits a transaction with no durable prepare recordFalseFalsePassed
Recovery reverses a previously recorded final decisionFalseFalsePassed
Prepared data becomes visible after losing its write locksFalseFalsePassed
unrelated tracing metadataTrueTruePassed
repeat validation is pureTrueTruePassed
two independent violations in variantFalseFalsePassed

SHA-256 / 67520ce943cd50c6ca66130d7e489d7f48b79714fec4ab46562738e376c1dde2

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(r):
    return (r['decision_known'] in ['commit','abort']) and (r['transaction_identity'][0] == r['transaction_identity'][1]) and (r['prepare_record'] is True) and (r['decision_consistent'][0] is None or r['decision_consistent'][0] == r['decision_consistent'][1]) and (set(r['locks_retained'][0]) <= set(r['locks_retained'][1]))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
r = {'decision_known': 'commit', 'transaction_identity': ['t2', 't2'], 'prepare_record': True, 'decision_consistent': ['commit', 'commit'], 'locks_retained': [['k1'], ['k1', 'k2']]}
check('valid operation', solve(r), True)
check('An uncertain participant guesses commit without evidence', solve(dict(r, **{'decision_known': 'unknown'})), False)
check('Recovery applies another transaction decision', solve(dict(r, **{'transaction_identity': ['t1', 't2']})), False)
check('Recovery commits a transaction with no durable prepare record', solve(dict(r, **{'prepare_record': False})), False)
check('Recovery reverses a previously recorded final decision', solve(dict(r, **{'decision_consistent': ['abort', 'commit']})), False)
check('Prepared data becomes visible after losing its write locks', solve(dict(r, **{'locks_retained': [['k1'], ['k2']]})), False)
check('unrelated tracing metadata', solve(dict(r, trace='run-'+str(N))), True)
check('repeat validation is pure', solve(r), True)
invalid = {'decision_known': 'unknown', 'transaction_identity': ['t1', 't2'], 'prepare_record': False, 'decision_consistent': ['abort', 'commit'], 'locks_retained': [['k1'], ['k2']]}
keys = list(invalid)
pair = {keys[N % len(keys)]: invalid[keys[N % len(keys)]], keys[(N+1) % len(keys)]: invalid[keys[(N+1) % len(keys)]]}
check('two independent violations in variant', solve(dict(r, **pair)), False)
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 fixtureActualExpectedOutcome
valid operationTrueTruePassed
An uncertain participant guesses commit without evidenceFalseFalsePassed
Recovery applies another transaction decisionFalseFalsePassed
Recovery commits a transaction with no durable prepare recordFalseFalsePassed
Recovery reverses a previously recorded final decisionFalseFalsePassed
Prepared data becomes visible after losing its write locksFalseFalsePassed
unrelated tracing metadataTrueTruePassed
repeat validation is pureTrueTruePassed
two independent violations in variantFalseFalsePassed

SHA-256 / 1bd48187b34651f0009e09de89e21e7f581688e1ac9f289c816366708eeb4900

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:37:02.962759+00:00.

Case digest / 9113ed0d6b8ff076bcd657a2e8dc25abfa2f32146309e0e2edf7519f21ac3b8a