FA-58211 / Double-entry ledger accounting / Open access
Journal void and reversal linkage: duplicate post detection · case 01
Posting a new entry reuses the id of a voided entry and resurrects it.
ROOT CAUSE
The duplicate check considers only posted entries.
VERIFIED REPAIR
Refuse any post whose id exists with any status.
Unsuccessful approach: Excluding only reversals still lets posts overwrite reversal entries.
Case contract
x = [['post', id, amount] | ['void', target_id, reversal_id] | other]. Posting an existing id is an error 'duplicate'. Voiding needs a known target ('unknown'), whose status is 'posted' ('not_voidable' for voided entries and reversals) and an unused reversal id ('duplicate'), checked in that order. A void marks the target 'voided' and creates a 'reversal' entry with the negated amount. Other commands give 'bad_command'. Return {'status', 'balance': sum of all amounts, 'errors': [[index, reason]]}.
Why this case matters
Ledger software must keep debits equal to credits and apply normal-balance, period and cutoff rules exactly; small sign or boundary slips silently misstate financial statements.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
status = {}
amounts = {}
errors = []
for i, cmd in enumerate(x):
if cmd[0] == 'post':
_, eid, amt = cmd
if eid in status and status[eid] == 'posted':
errors.append([i, 'duplicate'])
continue
status[eid] = 'posted'
amounts[eid] = amt
elif cmd[0] == 'void':
_, target, new = cmd
if target not in status:
errors.append([i, 'unknown'])
elif status[target] != 'posted':
errors.append([i, 'not_voidable'])
elif new in status:
errors.append([i, 'duplicate'])
else:
status[target] = 'voided'
status[new] = 'reversal'
amounts[new] = -amounts[target]
else:
errors.append([i, 'bad_command'])
return {'status': status, 'balance': sum(amounts.values()), 'errors': errors}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: duplicate post detection', [['post', 'A', 999], ['post', 'D', -40], ['void', 'R1', 'R1'], ['post', 'B', 999], ['void', 'B', 'R3'], ['post', 'R1', 999], ['post', 'B', 250]], {'status': {'A': 'posted', 'D': 'posted', 'B': 'voided', 'R3': 'reversal', 'R1': 'posted'}, 'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'D', 999], ['void', 'D', 'R1'], ['void', 'C', 'R3'], ['void', 'A', 'D'], ['post', 'A', 100], ['post', 'R1', -40], ['post', 'C', 999], ['post', 'B', 999]], {'status': {'D': 'voided', 'R1': 'reversal', 'A': 'posted', 'C': 'posted', 'B': 'posted'}, 'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 1', [['edit', 'A', 5], ['post', 'C', 999], ['void', 'C', 'R2'], ['void', 'R3', 'D']], {'status': {'C': 'voided', 'R2': 'reversal'}, 'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']]}], ['control 2', [['post', 'R1', -40], ['post', 'R1', 100], ['post', 'D', 999], ['edit', 'A', 5], ['void', 'R1', 'D'], ['void', 'R1', 'R2'], ['post', 'D', 999], ['void', 'R1', 'R1']], {'status': {'R1': 'voided', 'D': 'posted', 'R2': 'reversal'}, 'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']]}], ['control 3', [['post', 'C', 250], ['edit', 'A', 5], ['edit', 'A', 5], ['void', 'R1', 'D']], {'status': {'C': 'posted'}, 'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']]}], ['control 4', [['post', 'C', 100], ['post', 'D', 100], ['post', 'R1', 250], ['post', 'B', 250], ['void', 'C', 'R2'], ['void', 'B', 'R2']], {'status': {'C': 'voided', 'D': 'posted', 'R1': 'posted', 'B': 'posted', 'R2': 'reversal'}, 'balance': 600, 'errors': [[5, 'duplicate']]}], ['control 5', [['void', 'R2', 'D'], ['post', 'D', 999], ['post', 'D', 999], ['post', 'R1', 100], ['void', 'A', 'D']], {'status': {'D': 'posted', 'R1': 'posted'}, 'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']]}]], [['regression: duplicate post detection', [['post', 'D', 250], ['void', 'C', 'R2'], ['void', 'D', 'R3'], ['post', 'C', -40], ['post', 'C', 250], ['post', 'D', 999], ['post', 'A', -40], ['post', 'A', -40]], {'status': {'D': 'voided', 'R3': 'reversal', 'C': 'posted', 'A': 'posted'}, 'balance': -80, 'errors': [[1, 'unknown'], [4, 'duplicate'], [5, 'duplicate'], [7, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'B', -40], ['post', 'B', 250], ['void', 'B', 'R1'], ['post', 'R1', 100], ['post', 'C', -40], ['void', 'R1', 'R3'], ['post', 'A', 250], ['void', 'R1', 'R1']], {'status': {'B': 'voided', 'R1': 'reversal', 'C': 'posted', 'A': 'posted'}, 'balance': 210, 'errors': [[1, 'duplicate'], [3, 'duplicate'], [5, 'not_voidable'], [7, 'not_voidable']]}], ['control 1', [['post', 'B', 250], ['post', 'C', 250], ['edit', 'A', 5], ['post', 'B', 250], ['post', 'B', 100]], {'status': {'B': 'posted', 'C': 'posted'}, 'balance': 500, 'errors': [[2, 'bad_command'], [3, 'duplicate'], [4, 'duplicate']]}], ['control 2', [['post', 'B', 250], ['void', 'D', 'R3'], ['post', 'D', -40], ['post', 'A', -40], ['void', 'R3', 'R1'], ['void', 'R2', 'R3'], ['post', 'R1', -40], ['void', 'B', 'R1']], {'status': {'B': 'posted', 'D': 'posted', 'A': 'posted', 'R1': 'posted'}, 'balance': 130, 'errors': [[1, 'unknown'], [4, 'unknown'], [5, 'unknown'], [7, 'duplicate']]}], ['control 3', [['post', 'R1', -40], ['post', 'B', 250], ['post', 'C', 250], ['void', 'R2', 'R3']], {'status': {'R1': 'posted', 'B': 'posted', 'C': 'posted'}, 'balance': 460, 'errors': [[3, 'unknown']]}], ['control 4', [['post', 'A', 999], ['void', 'R1', 'R3'], ['void', 'R2', 'R2'], ['post', 'R1', 999]], {'status': {'A': 'posted', 'R1': 'posted'}, 'balance': 1998, 'errors': [[1, 'unknown'], [2, 'unknown']]}], ['control 5', [['void', 'C', 'D'], ['void', 'D', 'R1'], ['void', 'R3', 'D'], ['post', 'A', -40], ['post', 'D', 999], ['post', 'C', -40], ['void', 'R1', 'R3']], {'status': {'A': 'posted', 'D': 'posted', 'C': 'posted'}, 'balance': 919, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [6, 'unknown']]}]], [['regression: duplicate post detection', [['void', 'B', 'D'], ['post', 'C', -40], ['void', 'C', 'R2'], ['void', 'R3', 'R2'], ['post', 'R1', 100], ['post', 'C', -40], ['void', 'R2', 'D']], {'status': {'C': 'voided', 'R2': 'reversal', 'R1': 'posted'}, 'balance': 100, 'errors': [[0, 'unknown'], [3, 'unknown'], [5, 'duplicate'], [6, 'not_voidable']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'A', 999], ['void', 'A', 'R1'], ['post', 'R1', 999], ['post', 'D', 250], ['void', 'R2', 'R1'], ['post', 'B', 100], ['void', 'R1', 'R3']], {'status': {'A': 'voided', 'R1': 'reversal', 'D': 'posted', 'B': 'posted'}, 'balance': 350, 'errors': [[2, 'duplicate'], [4, 'unknown'], [6, 'not_voidable']]}], ['control 1', [['void', 'R1', 'R3'], ['void', 'A', 'R3'], ['void', 'R3', 'R1']], {'status': {}, 'balance': 0, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown']]}], ['control 2', [['void', 'C', 'R3'], ['void', 'R1', 'R3'], ['void', 'R2', 'R1'], ['void', 'R1', 'R1'], ['void', 'C', 'D'], ['void', 'A', 'R1'], ['post', 'D', 999]], {'status': {'D': 'posted'}, 'balance': 999, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [3, 'unknown'], [4, 'unknown'], [5, 'unknown']]}], ['control 3', [['post', 'D', -40], ['void', 'R3', 'R1'], ['post', 'B', 100], ['post', 'R1', 250], ['void', 'C', 'D'], ['post', 'A', 999], ['void', 'R2', 'R2']], {'status': {'D': 'posted', 'B': 'posted', 'R1': 'posted', 'A': 'posted'}, 'balance': 1309, 'errors': [[1, 'unknown'], [4, 'unknown'], [6, 'unknown']]}], ['control 4', [['edit', 'A', 5], ['post', 'R1', -40], ['post', 'C', 100], ['post', 'C', 100], ['post', 'R1', 100], ['void', 'R2', 'D'], ['post', 'B', -40]], {'status': {'R1': 'posted', 'C': 'posted', 'B': 'posted'}, 'balance': 20, 'errors': [[0, 'bad_command'], [3, 'duplicate'], [4, 'duplicate'], [5, 'unknown']]}], ['control 5', [['void', 'R3', 'R1'], ['post', 'D', -40], ['void', 'R3', 'R1'], ['post', 'R1', 100], ['post', 'A', 250], ['void', 'R1', 'R3'], ['void', 'A', 'D'], ['void', 'R1', 'R1']], {'status': {'D': 'posted', 'R1': 'voided', 'A': 'posted', 'R3': 'reversal'}, 'balance': 210, 'errors': [[0, 'unknown'], [2, 'unknown'], [6, 'duplicate'], [7, 'not_voidable']]}]], [['regression: duplicate post detection', [['void', 'R3', 'R2'], ['post', 'R1', -40], ['post', 'D', 999], ['void', 'D', 'R2'], ['post', 'A', 999], ['post', 'D', 999]], {'status': {'R1': 'posted', 'D': 'voided', 'R2': 'reversal', 'A': 'posted'}, 'balance': 959, 'errors': [[0, 'unknown'], [5, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['void', 'R2', 'R3'], ['post', 'B', 100], ['void', 'B', 'D'], ['void', 'R3', 'R3'], ['post', 'A', 100], ['post', 'D', 250]], {'status': {'B': 'voided', 'D': 'reversal', 'A': 'posted'}, 'balance': 100, 'errors': [[0, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 1', [['void', 'A', 'R1'], ['void', 'A', 'R1'], ['void', 'B', 'R3'], ['post', 'C', 100], ['post', 'B', -40], ['edit', 'A', 5], ['void', 'R2', 'D']], {'status': {'C': 'posted', 'B': 'posted'}, 'balance': 60, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [5, 'bad_command'], [6, 'unknown']]}], ['control 2', [['void', 'D', 'R1'], ['post', 'D', -40], ['post', 'A', 100], ['void', 'A', 'R1'], ['void', 'A', 'R3']], {'status': {'D': 'posted', 'A': 'voided', 'R1': 'reversal'}, 'balance': -40, 'errors': [[0, 'unknown'], [4, 'not_voidable']]}], ['control 3', [['void', 'D', 'R2'], ['void', 'R3', 'R3'], ['post', 'B', 250], ['void', 'D', 'D'], ['post', 'C', 999], ['post', 'B', -40]], {'status': {'B': 'posted', 'C': 'posted'}, 'balance': 1249, 'errors': [[0, 'unknown'], [1, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 4', [['post', 'R1', -40], ['void', 'D', 'R1'], ['post', 'A', 250], ['void', 'R1', 'D']], {'status': {'R1': 'voided', 'A': 'posted', 'D': 'reversal'}, 'balance': 250, 'errors': [[1, 'unknown']]}], ['control 5', [['edit', 'A', 5], ['edit', 'A', 5], ['post', 'D', 100], ['post', 'B', 999]], {'status': {'D': 'posted', 'B': 'posted'}, 'balance': 1099, 'errors': [[0, 'bad_command'], [1, 'bad_command']]}]], [['regression: duplicate post detection', [['void', 'D', 'R3'], ['void', 'D', 'D'], ['edit', 'A', 5], ['post', 'B', 999], ['post', 'D', 250], ['void', 'B', 'R3'], ['post', 'R1', 999], ['post', 'B', 250]], {'status': {'B': 'voided', 'D': 'posted', 'R3': 'reversal', 'R1': 'posted'}, 'balance': 1249, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'bad_command'], [7, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['void', 'C', 'D'], ['post', 'B', 100], ['void', 'B', 'R1'], ['post', 'R1', 999], ['void', 'R3', 'D'], ['void', 'R2', 'R3'], ['void', 'B', 'R2'], ['void', 'R3', 'R1']], {'status': {'B': 'voided', 'R1': 'reversal'}, 'balance': 0, 'errors': [[0, 'unknown'], [3, 'duplicate'], [4, 'unknown'], [5, 'unknown'], [6, 'not_voidable'], [7, 'unknown']]}], ['control 1', [['void', 'R2', 'R1'], ['void', 'B', 'D'], ['post', 'C', 250]], {'status': {'C': 'posted'}, 'balance': 250, 'errors': [[0, 'unknown'], [1, 'unknown']]}], ['control 2', [['void', 'A', 'R1'], ['post', 'A', -40], ['post', 'A', -40], ['post', 'A', 999], ['void', 'R1', 'R2']], {'status': {'A': 'posted'}, 'balance': -40, 'errors': [[0, 'unknown'], [2, 'duplicate'], [3, 'duplicate'], [4, 'unknown']]}], ['control 3', [['post', 'B', 250], ['post', 'D', 100], ['post', 'A', 999], ['post', 'D', -40]], {'status': {'B': 'posted', 'D': 'posted', 'A': 'posted'}, 'balance': 1349, 'errors': [[3, 'duplicate']]}], ['control 4', [['void', 'C', 'R2'], ['void', 'B', 'R3'], ['void', 'R1', 'R2'], ['void', 'D', 'D'], ['void', 'R3', 'R2'], ['post', 'C', 250], ['post', 'A', 999], ['post', 'R1', 100]], {'status': {'C': 'posted', 'A': 'posted', 'R1': 'posted'}, 'balance': 1349, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [3, 'unknown'], [4, 'unknown']]}], ['control 5', [['void', 'R1', 'R3'], ['post', 'C', 999], ['post', 'R1', -40], ['post', 'D', 999], ['post', 'A', 250], ['post', 'B', 250], ['void', 'R2', 'D']], {'status': {'C': 'posted', 'R1': 'posted', 'D': 'posted', 'A': 'posted', 'B': 'posted'}, 'balance': 2458, 'errors': [[0, 'unknown'], [6, 'unknown']]}]]]
for label, args, expected in fixtures[N-1]:
try:
actual = solve(args)
except Exception as exc:
actual = 'raised ' + type(exc).__name__
check(label, actual, 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 |
|---|---|---|---|
| regression: duplicate post detection | {'balance': 1209, 'errors': [[2, 'unknown']], 'status': {'A': 'posted', 'B': 'posted', 'D': 'posted', 'R1': 'posted', 'R3': 'reversal'}} | {'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']], 'status': {'A': 'posted', 'B': 'voided', 'D': 'posted', 'R1': 'posted', 'R3': 'reversal'}} | Failed |
| regression: duplicate post detection, partial-repair probe | {'balance': 3057, 'errors': [[2, 'unknown'], [3, 'unknown']], 'status': {'A': 'posted', 'B': 'posted', 'C': 'posted', 'D': 'voided', 'R1': 'posted'}} | {'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']], 'status': {'A': 'posted', 'B': 'posted', 'C': 'posted', 'D': 'voided', 'R1': 'reversal'}} | Failed |
| control 1 | {'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']], 'status': {'C': 'voided', 'R2': 'reversal'}} | {'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']], 'status': {'C': 'voided', 'R2': 'reversal'}} | Passed |
| control 2 | {'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']], 'status': {'D': 'posted', 'R1': 'voided', 'R2': 'reversal'}} | {'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']], 'status': {'D': 'posted', 'R1': 'voided', 'R2': 'reversal'}} | Passed |
| control 3 | {'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']], 'status': {'C': 'posted'}} | {'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']], 'status': {'C': 'posted'}} | Passed |
| control 4 | {'balance': 600, 'errors': [[5, 'duplicate']], 'status': {'B': 'posted', 'C': 'voided', 'D': 'posted', 'R1': 'posted', 'R2': 'reversal'}} | {'balance': 600, 'errors': [[5, 'duplicate']], 'status': {'B': 'posted', 'C': 'voided', 'D': 'posted', 'R1': 'posted', 'R2': 'reversal'}} | Passed |
| control 5 | {'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']], 'status': {'D': 'posted', 'R1': 'posted'}} | {'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']], 'status': {'D': 'posted', 'R1': 'posted'}} | Passed |
SHA-256 / 5c8d0b1ebb497798494c3937ebc8365284d92ae92a0e9703d5a41884c2976a83
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
status = {}
amounts = {}
errors = []
for i, cmd in enumerate(x):
if cmd[0] == 'post':
_, eid, amt = cmd
if eid in status and status[eid] != 'reversal':
errors.append([i, 'duplicate'])
continue
status[eid] = 'posted'
amounts[eid] = amt
elif cmd[0] == 'void':
_, target, new = cmd
if target not in status:
errors.append([i, 'unknown'])
elif status[target] != 'posted':
errors.append([i, 'not_voidable'])
elif new in status:
errors.append([i, 'duplicate'])
else:
status[target] = 'voided'
status[new] = 'reversal'
amounts[new] = -amounts[target]
else:
errors.append([i, 'bad_command'])
return {'status': status, 'balance': sum(amounts.values()), 'errors': errors}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: duplicate post detection', [['post', 'A', 999], ['post', 'D', -40], ['void', 'R1', 'R1'], ['post', 'B', 999], ['void', 'B', 'R3'], ['post', 'R1', 999], ['post', 'B', 250]], {'status': {'A': 'posted', 'D': 'posted', 'B': 'voided', 'R3': 'reversal', 'R1': 'posted'}, 'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'D', 999], ['void', 'D', 'R1'], ['void', 'C', 'R3'], ['void', 'A', 'D'], ['post', 'A', 100], ['post', 'R1', -40], ['post', 'C', 999], ['post', 'B', 999]], {'status': {'D': 'voided', 'R1': 'reversal', 'A': 'posted', 'C': 'posted', 'B': 'posted'}, 'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 1', [['edit', 'A', 5], ['post', 'C', 999], ['void', 'C', 'R2'], ['void', 'R3', 'D']], {'status': {'C': 'voided', 'R2': 'reversal'}, 'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']]}], ['control 2', [['post', 'R1', -40], ['post', 'R1', 100], ['post', 'D', 999], ['edit', 'A', 5], ['void', 'R1', 'D'], ['void', 'R1', 'R2'], ['post', 'D', 999], ['void', 'R1', 'R1']], {'status': {'R1': 'voided', 'D': 'posted', 'R2': 'reversal'}, 'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']]}], ['control 3', [['post', 'C', 250], ['edit', 'A', 5], ['edit', 'A', 5], ['void', 'R1', 'D']], {'status': {'C': 'posted'}, 'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']]}], ['control 4', [['post', 'C', 100], ['post', 'D', 100], ['post', 'R1', 250], ['post', 'B', 250], ['void', 'C', 'R2'], ['void', 'B', 'R2']], {'status': {'C': 'voided', 'D': 'posted', 'R1': 'posted', 'B': 'posted', 'R2': 'reversal'}, 'balance': 600, 'errors': [[5, 'duplicate']]}], ['control 5', [['void', 'R2', 'D'], ['post', 'D', 999], ['post', 'D', 999], ['post', 'R1', 100], ['void', 'A', 'D']], {'status': {'D': 'posted', 'R1': 'posted'}, 'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']]}]], [['regression: duplicate post detection', [['post', 'D', 250], ['void', 'C', 'R2'], ['void', 'D', 'R3'], ['post', 'C', -40], ['post', 'C', 250], ['post', 'D', 999], ['post', 'A', -40], ['post', 'A', -40]], {'status': {'D': 'voided', 'R3': 'reversal', 'C': 'posted', 'A': 'posted'}, 'balance': -80, 'errors': [[1, 'unknown'], [4, 'duplicate'], [5, 'duplicate'], [7, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'B', -40], ['post', 'B', 250], ['void', 'B', 'R1'], ['post', 'R1', 100], ['post', 'C', -40], ['void', 'R1', 'R3'], ['post', 'A', 250], ['void', 'R1', 'R1']], {'status': {'B': 'voided', 'R1': 'reversal', 'C': 'posted', 'A': 'posted'}, 'balance': 210, 'errors': [[1, 'duplicate'], [3, 'duplicate'], [5, 'not_voidable'], [7, 'not_voidable']]}], ['control 1', [['post', 'B', 250], ['post', 'C', 250], ['edit', 'A', 5], ['post', 'B', 250], ['post', 'B', 100]], {'status': {'B': 'posted', 'C': 'posted'}, 'balance': 500, 'errors': [[2, 'bad_command'], [3, 'duplicate'], [4, 'duplicate']]}], ['control 2', [['post', 'B', 250], ['void', 'D', 'R3'], ['post', 'D', -40], ['post', 'A', -40], ['void', 'R3', 'R1'], ['void', 'R2', 'R3'], ['post', 'R1', -40], ['void', 'B', 'R1']], {'status': {'B': 'posted', 'D': 'posted', 'A': 'posted', 'R1': 'posted'}, 'balance': 130, 'errors': [[1, 'unknown'], [4, 'unknown'], [5, 'unknown'], [7, 'duplicate']]}], ['control 3', [['post', 'R1', -40], ['post', 'B', 250], ['post', 'C', 250], ['void', 'R2', 'R3']], {'status': {'R1': 'posted', 'B': 'posted', 'C': 'posted'}, 'balance': 460, 'errors': [[3, 'unknown']]}], ['control 4', [['post', 'A', 999], ['void', 'R1', 'R3'], ['void', 'R2', 'R2'], ['post', 'R1', 999]], {'status': {'A': 'posted', 'R1': 'posted'}, 'balance': 1998, 'errors': [[1, 'unknown'], [2, 'unknown']]}], ['control 5', [['void', 'C', 'D'], ['void', 'D', 'R1'], ['void', 'R3', 'D'], ['post', 'A', -40], ['post', 'D', 999], ['post', 'C', -40], ['void', 'R1', 'R3']], {'status': {'A': 'posted', 'D': 'posted', 'C': 'posted'}, 'balance': 919, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [6, 'unknown']]}]], [['regression: duplicate post detection', [['void', 'B', 'D'], ['post', 'C', -40], ['void', 'C', 'R2'], ['void', 'R3', 'R2'], ['post', 'R1', 100], ['post', 'C', -40], ['void', 'R2', 'D']], {'status': {'C': 'voided', 'R2': 'reversal', 'R1': 'posted'}, 'balance': 100, 'errors': [[0, 'unknown'], [3, 'unknown'], [5, 'duplicate'], [6, 'not_voidable']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'A', 999], ['void', 'A', 'R1'], ['post', 'R1', 999], ['post', 'D', 250], ['void', 'R2', 'R1'], ['post', 'B', 100], ['void', 'R1', 'R3']], {'status': {'A': 'voided', 'R1': 'reversal', 'D': 'posted', 'B': 'posted'}, 'balance': 350, 'errors': [[2, 'duplicate'], [4, 'unknown'], [6, 'not_voidable']]}], ['control 1', [['void', 'R1', 'R3'], ['void', 'A', 'R3'], ['void', 'R3', 'R1']], {'status': {}, 'balance': 0, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown']]}], ['control 2', [['void', 'C', 'R3'], ['void', 'R1', 'R3'], ['void', 'R2', 'R1'], ['void', 'R1', 'R1'], ['void', 'C', 'D'], ['void', 'A', 'R1'], ['post', 'D', 999]], {'status': {'D': 'posted'}, 'balance': 999, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [3, 'unknown'], [4, 'unknown'], [5, 'unknown']]}], ['control 3', [['post', 'D', -40], ['void', 'R3', 'R1'], ['post', 'B', 100], ['post', 'R1', 250], ['void', 'C', 'D'], ['post', 'A', 999], ['void', 'R2', 'R2']], {'status': {'D': 'posted', 'B': 'posted', 'R1': 'posted', 'A': 'posted'}, 'balance': 1309, 'errors': [[1, 'unknown'], [4, 'unknown'], [6, 'unknown']]}], ['control 4', [['edit', 'A', 5], ['post', 'R1', -40], ['post', 'C', 100], ['post', 'C', 100], ['post', 'R1', 100], ['void', 'R2', 'D'], ['post', 'B', -40]], {'status': {'R1': 'posted', 'C': 'posted', 'B': 'posted'}, 'balance': 20, 'errors': [[0, 'bad_command'], [3, 'duplicate'], [4, 'duplicate'], [5, 'unknown']]}], ['control 5', [['void', 'R3', 'R1'], ['post', 'D', -40], ['void', 'R3', 'R1'], ['post', 'R1', 100], ['post', 'A', 250], ['void', 'R1', 'R3'], ['void', 'A', 'D'], ['void', 'R1', 'R1']], {'status': {'D': 'posted', 'R1': 'voided', 'A': 'posted', 'R3': 'reversal'}, 'balance': 210, 'errors': [[0, 'unknown'], [2, 'unknown'], [6, 'duplicate'], [7, 'not_voidable']]}]], [['regression: duplicate post detection', [['void', 'R3', 'R2'], ['post', 'R1', -40], ['post', 'D', 999], ['void', 'D', 'R2'], ['post', 'A', 999], ['post', 'D', 999]], {'status': {'R1': 'posted', 'D': 'voided', 'R2': 'reversal', 'A': 'posted'}, 'balance': 959, 'errors': [[0, 'unknown'], [5, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['void', 'R2', 'R3'], ['post', 'B', 100], ['void', 'B', 'D'], ['void', 'R3', 'R3'], ['post', 'A', 100], ['post', 'D', 250]], {'status': {'B': 'voided', 'D': 'reversal', 'A': 'posted'}, 'balance': 100, 'errors': [[0, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 1', [['void', 'A', 'R1'], ['void', 'A', 'R1'], ['void', 'B', 'R3'], ['post', 'C', 100], ['post', 'B', -40], ['edit', 'A', 5], ['void', 'R2', 'D']], {'status': {'C': 'posted', 'B': 'posted'}, 'balance': 60, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [5, 'bad_command'], [6, 'unknown']]}], ['control 2', [['void', 'D', 'R1'], ['post', 'D', -40], ['post', 'A', 100], ['void', 'A', 'R1'], ['void', 'A', 'R3']], {'status': {'D': 'posted', 'A': 'voided', 'R1': 'reversal'}, 'balance': -40, 'errors': [[0, 'unknown'], [4, 'not_voidable']]}], ['control 3', [['void', 'D', 'R2'], ['void', 'R3', 'R3'], ['post', 'B', 250], ['void', 'D', 'D'], ['post', 'C', 999], ['post', 'B', -40]], {'status': {'B': 'posted', 'C': 'posted'}, 'balance': 1249, 'errors': [[0, 'unknown'], [1, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 4', [['post', 'R1', -40], ['void', 'D', 'R1'], ['post', 'A', 250], ['void', 'R1', 'D']], {'status': {'R1': 'voided', 'A': 'posted', 'D': 'reversal'}, 'balance': 250, 'errors': [[1, 'unknown']]}], ['control 5', [['edit', 'A', 5], ['edit', 'A', 5], ['post', 'D', 100], ['post', 'B', 999]], {'status': {'D': 'posted', 'B': 'posted'}, 'balance': 1099, 'errors': [[0, 'bad_command'], [1, 'bad_command']]}]], [['regression: duplicate post detection', [['void', 'D', 'R3'], ['void', 'D', 'D'], ['edit', 'A', 5], ['post', 'B', 999], ['post', 'D', 250], ['void', 'B', 'R3'], ['post', 'R1', 999], ['post', 'B', 250]], {'status': {'B': 'voided', 'D': 'posted', 'R3': 'reversal', 'R1': 'posted'}, 'balance': 1249, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'bad_command'], [7, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['void', 'C', 'D'], ['post', 'B', 100], ['void', 'B', 'R1'], ['post', 'R1', 999], ['void', 'R3', 'D'], ['void', 'R2', 'R3'], ['void', 'B', 'R2'], ['void', 'R3', 'R1']], {'status': {'B': 'voided', 'R1': 'reversal'}, 'balance': 0, 'errors': [[0, 'unknown'], [3, 'duplicate'], [4, 'unknown'], [5, 'unknown'], [6, 'not_voidable'], [7, 'unknown']]}], ['control 1', [['void', 'R2', 'R1'], ['void', 'B', 'D'], ['post', 'C', 250]], {'status': {'C': 'posted'}, 'balance': 250, 'errors': [[0, 'unknown'], [1, 'unknown']]}], ['control 2', [['void', 'A', 'R1'], ['post', 'A', -40], ['post', 'A', -40], ['post', 'A', 999], ['void', 'R1', 'R2']], {'status': {'A': 'posted'}, 'balance': -40, 'errors': [[0, 'unknown'], [2, 'duplicate'], [3, 'duplicate'], [4, 'unknown']]}], ['control 3', [['post', 'B', 250], ['post', 'D', 100], ['post', 'A', 999], ['post', 'D', -40]], {'status': {'B': 'posted', 'D': 'posted', 'A': 'posted'}, 'balance': 1349, 'errors': [[3, 'duplicate']]}], ['control 4', [['void', 'C', 'R2'], ['void', 'B', 'R3'], ['void', 'R1', 'R2'], ['void', 'D', 'D'], ['void', 'R3', 'R2'], ['post', 'C', 250], ['post', 'A', 999], ['post', 'R1', 100]], {'status': {'C': 'posted', 'A': 'posted', 'R1': 'posted'}, 'balance': 1349, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [3, 'unknown'], [4, 'unknown']]}], ['control 5', [['void', 'R1', 'R3'], ['post', 'C', 999], ['post', 'R1', -40], ['post', 'D', 999], ['post', 'A', 250], ['post', 'B', 250], ['void', 'R2', 'D']], {'status': {'C': 'posted', 'R1': 'posted', 'D': 'posted', 'A': 'posted', 'B': 'posted'}, 'balance': 2458, 'errors': [[0, 'unknown'], [6, 'unknown']]}]]]
for label, args, expected in fixtures[N-1]:
try:
actual = solve(args)
except Exception as exc:
actual = 'raised ' + type(exc).__name__
check(label, actual, 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 |
|---|---|---|---|
| regression: duplicate post detection | {'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']], 'status': {'A': 'posted', 'B': 'voided', 'D': 'posted', 'R1': 'posted', 'R3': 'reversal'}} | {'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']], 'status': {'A': 'posted', 'B': 'voided', 'D': 'posted', 'R1': 'posted', 'R3': 'reversal'}} | Passed |
| regression: duplicate post detection, partial-repair probe | {'balance': 3057, 'errors': [[2, 'unknown'], [3, 'unknown']], 'status': {'A': 'posted', 'B': 'posted', 'C': 'posted', 'D': 'voided', 'R1': 'posted'}} | {'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']], 'status': {'A': 'posted', 'B': 'posted', 'C': 'posted', 'D': 'voided', 'R1': 'reversal'}} | Failed |
| control 1 | {'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']], 'status': {'C': 'voided', 'R2': 'reversal'}} | {'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']], 'status': {'C': 'voided', 'R2': 'reversal'}} | Passed |
| control 2 | {'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']], 'status': {'D': 'posted', 'R1': 'voided', 'R2': 'reversal'}} | {'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']], 'status': {'D': 'posted', 'R1': 'voided', 'R2': 'reversal'}} | Passed |
| control 3 | {'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']], 'status': {'C': 'posted'}} | {'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']], 'status': {'C': 'posted'}} | Passed |
| control 4 | {'balance': 600, 'errors': [[5, 'duplicate']], 'status': {'B': 'posted', 'C': 'voided', 'D': 'posted', 'R1': 'posted', 'R2': 'reversal'}} | {'balance': 600, 'errors': [[5, 'duplicate']], 'status': {'B': 'posted', 'C': 'voided', 'D': 'posted', 'R1': 'posted', 'R2': 'reversal'}} | Passed |
| control 5 | {'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']], 'status': {'D': 'posted', 'R1': 'posted'}} | {'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']], 'status': {'D': 'posted', 'R1': 'posted'}} | Passed |
SHA-256 / 3e458306283bf2c44df893c1f6dd80fd165bce9589b6a46f417c3ef1caa8a7fa
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
status = {}
amounts = {}
errors = []
for i, cmd in enumerate(x):
if cmd[0] == 'post':
_, eid, amt = cmd
if eid in status:
errors.append([i, 'duplicate'])
continue
status[eid] = 'posted'
amounts[eid] = amt
elif cmd[0] == 'void':
_, target, new = cmd
if target not in status:
errors.append([i, 'unknown'])
elif status[target] != 'posted':
errors.append([i, 'not_voidable'])
elif new in status:
errors.append([i, 'duplicate'])
else:
status[target] = 'voided'
status[new] = 'reversal'
amounts[new] = -amounts[target]
else:
errors.append([i, 'bad_command'])
return {'status': status, 'balance': sum(amounts.values()), 'errors': errors}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: duplicate post detection', [['post', 'A', 999], ['post', 'D', -40], ['void', 'R1', 'R1'], ['post', 'B', 999], ['void', 'B', 'R3'], ['post', 'R1', 999], ['post', 'B', 250]], {'status': {'A': 'posted', 'D': 'posted', 'B': 'voided', 'R3': 'reversal', 'R1': 'posted'}, 'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'D', 999], ['void', 'D', 'R1'], ['void', 'C', 'R3'], ['void', 'A', 'D'], ['post', 'A', 100], ['post', 'R1', -40], ['post', 'C', 999], ['post', 'B', 999]], {'status': {'D': 'voided', 'R1': 'reversal', 'A': 'posted', 'C': 'posted', 'B': 'posted'}, 'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 1', [['edit', 'A', 5], ['post', 'C', 999], ['void', 'C', 'R2'], ['void', 'R3', 'D']], {'status': {'C': 'voided', 'R2': 'reversal'}, 'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']]}], ['control 2', [['post', 'R1', -40], ['post', 'R1', 100], ['post', 'D', 999], ['edit', 'A', 5], ['void', 'R1', 'D'], ['void', 'R1', 'R2'], ['post', 'D', 999], ['void', 'R1', 'R1']], {'status': {'R1': 'voided', 'D': 'posted', 'R2': 'reversal'}, 'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']]}], ['control 3', [['post', 'C', 250], ['edit', 'A', 5], ['edit', 'A', 5], ['void', 'R1', 'D']], {'status': {'C': 'posted'}, 'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']]}], ['control 4', [['post', 'C', 100], ['post', 'D', 100], ['post', 'R1', 250], ['post', 'B', 250], ['void', 'C', 'R2'], ['void', 'B', 'R2']], {'status': {'C': 'voided', 'D': 'posted', 'R1': 'posted', 'B': 'posted', 'R2': 'reversal'}, 'balance': 600, 'errors': [[5, 'duplicate']]}], ['control 5', [['void', 'R2', 'D'], ['post', 'D', 999], ['post', 'D', 999], ['post', 'R1', 100], ['void', 'A', 'D']], {'status': {'D': 'posted', 'R1': 'posted'}, 'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']]}]], [['regression: duplicate post detection', [['post', 'D', 250], ['void', 'C', 'R2'], ['void', 'D', 'R3'], ['post', 'C', -40], ['post', 'C', 250], ['post', 'D', 999], ['post', 'A', -40], ['post', 'A', -40]], {'status': {'D': 'voided', 'R3': 'reversal', 'C': 'posted', 'A': 'posted'}, 'balance': -80, 'errors': [[1, 'unknown'], [4, 'duplicate'], [5, 'duplicate'], [7, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'B', -40], ['post', 'B', 250], ['void', 'B', 'R1'], ['post', 'R1', 100], ['post', 'C', -40], ['void', 'R1', 'R3'], ['post', 'A', 250], ['void', 'R1', 'R1']], {'status': {'B': 'voided', 'R1': 'reversal', 'C': 'posted', 'A': 'posted'}, 'balance': 210, 'errors': [[1, 'duplicate'], [3, 'duplicate'], [5, 'not_voidable'], [7, 'not_voidable']]}], ['control 1', [['post', 'B', 250], ['post', 'C', 250], ['edit', 'A', 5], ['post', 'B', 250], ['post', 'B', 100]], {'status': {'B': 'posted', 'C': 'posted'}, 'balance': 500, 'errors': [[2, 'bad_command'], [3, 'duplicate'], [4, 'duplicate']]}], ['control 2', [['post', 'B', 250], ['void', 'D', 'R3'], ['post', 'D', -40], ['post', 'A', -40], ['void', 'R3', 'R1'], ['void', 'R2', 'R3'], ['post', 'R1', -40], ['void', 'B', 'R1']], {'status': {'B': 'posted', 'D': 'posted', 'A': 'posted', 'R1': 'posted'}, 'balance': 130, 'errors': [[1, 'unknown'], [4, 'unknown'], [5, 'unknown'], [7, 'duplicate']]}], ['control 3', [['post', 'R1', -40], ['post', 'B', 250], ['post', 'C', 250], ['void', 'R2', 'R3']], {'status': {'R1': 'posted', 'B': 'posted', 'C': 'posted'}, 'balance': 460, 'errors': [[3, 'unknown']]}], ['control 4', [['post', 'A', 999], ['void', 'R1', 'R3'], ['void', 'R2', 'R2'], ['post', 'R1', 999]], {'status': {'A': 'posted', 'R1': 'posted'}, 'balance': 1998, 'errors': [[1, 'unknown'], [2, 'unknown']]}], ['control 5', [['void', 'C', 'D'], ['void', 'D', 'R1'], ['void', 'R3', 'D'], ['post', 'A', -40], ['post', 'D', 999], ['post', 'C', -40], ['void', 'R1', 'R3']], {'status': {'A': 'posted', 'D': 'posted', 'C': 'posted'}, 'balance': 919, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [6, 'unknown']]}]], [['regression: duplicate post detection', [['void', 'B', 'D'], ['post', 'C', -40], ['void', 'C', 'R2'], ['void', 'R3', 'R2'], ['post', 'R1', 100], ['post', 'C', -40], ['void', 'R2', 'D']], {'status': {'C': 'voided', 'R2': 'reversal', 'R1': 'posted'}, 'balance': 100, 'errors': [[0, 'unknown'], [3, 'unknown'], [5, 'duplicate'], [6, 'not_voidable']]}], ['regression: duplicate post detection, partial-repair probe', [['post', 'A', 999], ['void', 'A', 'R1'], ['post', 'R1', 999], ['post', 'D', 250], ['void', 'R2', 'R1'], ['post', 'B', 100], ['void', 'R1', 'R3']], {'status': {'A': 'voided', 'R1': 'reversal', 'D': 'posted', 'B': 'posted'}, 'balance': 350, 'errors': [[2, 'duplicate'], [4, 'unknown'], [6, 'not_voidable']]}], ['control 1', [['void', 'R1', 'R3'], ['void', 'A', 'R3'], ['void', 'R3', 'R1']], {'status': {}, 'balance': 0, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown']]}], ['control 2', [['void', 'C', 'R3'], ['void', 'R1', 'R3'], ['void', 'R2', 'R1'], ['void', 'R1', 'R1'], ['void', 'C', 'D'], ['void', 'A', 'R1'], ['post', 'D', 999]], {'status': {'D': 'posted'}, 'balance': 999, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [3, 'unknown'], [4, 'unknown'], [5, 'unknown']]}], ['control 3', [['post', 'D', -40], ['void', 'R3', 'R1'], ['post', 'B', 100], ['post', 'R1', 250], ['void', 'C', 'D'], ['post', 'A', 999], ['void', 'R2', 'R2']], {'status': {'D': 'posted', 'B': 'posted', 'R1': 'posted', 'A': 'posted'}, 'balance': 1309, 'errors': [[1, 'unknown'], [4, 'unknown'], [6, 'unknown']]}], ['control 4', [['edit', 'A', 5], ['post', 'R1', -40], ['post', 'C', 100], ['post', 'C', 100], ['post', 'R1', 100], ['void', 'R2', 'D'], ['post', 'B', -40]], {'status': {'R1': 'posted', 'C': 'posted', 'B': 'posted'}, 'balance': 20, 'errors': [[0, 'bad_command'], [3, 'duplicate'], [4, 'duplicate'], [5, 'unknown']]}], ['control 5', [['void', 'R3', 'R1'], ['post', 'D', -40], ['void', 'R3', 'R1'], ['post', 'R1', 100], ['post', 'A', 250], ['void', 'R1', 'R3'], ['void', 'A', 'D'], ['void', 'R1', 'R1']], {'status': {'D': 'posted', 'R1': 'voided', 'A': 'posted', 'R3': 'reversal'}, 'balance': 210, 'errors': [[0, 'unknown'], [2, 'unknown'], [6, 'duplicate'], [7, 'not_voidable']]}]], [['regression: duplicate post detection', [['void', 'R3', 'R2'], ['post', 'R1', -40], ['post', 'D', 999], ['void', 'D', 'R2'], ['post', 'A', 999], ['post', 'D', 999]], {'status': {'R1': 'posted', 'D': 'voided', 'R2': 'reversal', 'A': 'posted'}, 'balance': 959, 'errors': [[0, 'unknown'], [5, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['void', 'R2', 'R3'], ['post', 'B', 100], ['void', 'B', 'D'], ['void', 'R3', 'R3'], ['post', 'A', 100], ['post', 'D', 250]], {'status': {'B': 'voided', 'D': 'reversal', 'A': 'posted'}, 'balance': 100, 'errors': [[0, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 1', [['void', 'A', 'R1'], ['void', 'A', 'R1'], ['void', 'B', 'R3'], ['post', 'C', 100], ['post', 'B', -40], ['edit', 'A', 5], ['void', 'R2', 'D']], {'status': {'C': 'posted', 'B': 'posted'}, 'balance': 60, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [5, 'bad_command'], [6, 'unknown']]}], ['control 2', [['void', 'D', 'R1'], ['post', 'D', -40], ['post', 'A', 100], ['void', 'A', 'R1'], ['void', 'A', 'R3']], {'status': {'D': 'posted', 'A': 'voided', 'R1': 'reversal'}, 'balance': -40, 'errors': [[0, 'unknown'], [4, 'not_voidable']]}], ['control 3', [['void', 'D', 'R2'], ['void', 'R3', 'R3'], ['post', 'B', 250], ['void', 'D', 'D'], ['post', 'C', 999], ['post', 'B', -40]], {'status': {'B': 'posted', 'C': 'posted'}, 'balance': 1249, 'errors': [[0, 'unknown'], [1, 'unknown'], [3, 'unknown'], [5, 'duplicate']]}], ['control 4', [['post', 'R1', -40], ['void', 'D', 'R1'], ['post', 'A', 250], ['void', 'R1', 'D']], {'status': {'R1': 'voided', 'A': 'posted', 'D': 'reversal'}, 'balance': 250, 'errors': [[1, 'unknown']]}], ['control 5', [['edit', 'A', 5], ['edit', 'A', 5], ['post', 'D', 100], ['post', 'B', 999]], {'status': {'D': 'posted', 'B': 'posted'}, 'balance': 1099, 'errors': [[0, 'bad_command'], [1, 'bad_command']]}]], [['regression: duplicate post detection', [['void', 'D', 'R3'], ['void', 'D', 'D'], ['edit', 'A', 5], ['post', 'B', 999], ['post', 'D', 250], ['void', 'B', 'R3'], ['post', 'R1', 999], ['post', 'B', 250]], {'status': {'B': 'voided', 'D': 'posted', 'R3': 'reversal', 'R1': 'posted'}, 'balance': 1249, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'bad_command'], [7, 'duplicate']]}], ['regression: duplicate post detection, partial-repair probe', [['void', 'C', 'D'], ['post', 'B', 100], ['void', 'B', 'R1'], ['post', 'R1', 999], ['void', 'R3', 'D'], ['void', 'R2', 'R3'], ['void', 'B', 'R2'], ['void', 'R3', 'R1']], {'status': {'B': 'voided', 'R1': 'reversal'}, 'balance': 0, 'errors': [[0, 'unknown'], [3, 'duplicate'], [4, 'unknown'], [5, 'unknown'], [6, 'not_voidable'], [7, 'unknown']]}], ['control 1', [['void', 'R2', 'R1'], ['void', 'B', 'D'], ['post', 'C', 250]], {'status': {'C': 'posted'}, 'balance': 250, 'errors': [[0, 'unknown'], [1, 'unknown']]}], ['control 2', [['void', 'A', 'R1'], ['post', 'A', -40], ['post', 'A', -40], ['post', 'A', 999], ['void', 'R1', 'R2']], {'status': {'A': 'posted'}, 'balance': -40, 'errors': [[0, 'unknown'], [2, 'duplicate'], [3, 'duplicate'], [4, 'unknown']]}], ['control 3', [['post', 'B', 250], ['post', 'D', 100], ['post', 'A', 999], ['post', 'D', -40]], {'status': {'B': 'posted', 'D': 'posted', 'A': 'posted'}, 'balance': 1349, 'errors': [[3, 'duplicate']]}], ['control 4', [['void', 'C', 'R2'], ['void', 'B', 'R3'], ['void', 'R1', 'R2'], ['void', 'D', 'D'], ['void', 'R3', 'R2'], ['post', 'C', 250], ['post', 'A', 999], ['post', 'R1', 100]], {'status': {'C': 'posted', 'A': 'posted', 'R1': 'posted'}, 'balance': 1349, 'errors': [[0, 'unknown'], [1, 'unknown'], [2, 'unknown'], [3, 'unknown'], [4, 'unknown']]}], ['control 5', [['void', 'R1', 'R3'], ['post', 'C', 999], ['post', 'R1', -40], ['post', 'D', 999], ['post', 'A', 250], ['post', 'B', 250], ['void', 'R2', 'D']], {'status': {'C': 'posted', 'R1': 'posted', 'D': 'posted', 'A': 'posted', 'B': 'posted'}, 'balance': 2458, 'errors': [[0, 'unknown'], [6, 'unknown']]}]]]
for label, args, expected in fixtures[N-1]:
try:
actual = solve(args)
except Exception as exc:
actual = 'raised ' + type(exc).__name__
check(label, actual, 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 |
|---|---|---|---|
| regression: duplicate post detection | {'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']], 'status': {'A': 'posted', 'B': 'voided', 'D': 'posted', 'R1': 'posted', 'R3': 'reversal'}} | {'balance': 1958, 'errors': [[2, 'unknown'], [6, 'duplicate']], 'status': {'A': 'posted', 'B': 'voided', 'D': 'posted', 'R1': 'posted', 'R3': 'reversal'}} | Passed |
| regression: duplicate post detection, partial-repair probe | {'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']], 'status': {'A': 'posted', 'B': 'posted', 'C': 'posted', 'D': 'voided', 'R1': 'reversal'}} | {'balance': 2098, 'errors': [[2, 'unknown'], [3, 'unknown'], [5, 'duplicate']], 'status': {'A': 'posted', 'B': 'posted', 'C': 'posted', 'D': 'voided', 'R1': 'reversal'}} | Passed |
| control 1 | {'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']], 'status': {'C': 'voided', 'R2': 'reversal'}} | {'balance': 0, 'errors': [[0, 'bad_command'], [3, 'unknown']], 'status': {'C': 'voided', 'R2': 'reversal'}} | Passed |
| control 2 | {'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']], 'status': {'D': 'posted', 'R1': 'voided', 'R2': 'reversal'}} | {'balance': 999, 'errors': [[1, 'duplicate'], [3, 'bad_command'], [4, 'duplicate'], [6, 'duplicate'], [7, 'not_voidable']], 'status': {'D': 'posted', 'R1': 'voided', 'R2': 'reversal'}} | Passed |
| control 3 | {'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']], 'status': {'C': 'posted'}} | {'balance': 250, 'errors': [[1, 'bad_command'], [2, 'bad_command'], [3, 'unknown']], 'status': {'C': 'posted'}} | Passed |
| control 4 | {'balance': 600, 'errors': [[5, 'duplicate']], 'status': {'B': 'posted', 'C': 'voided', 'D': 'posted', 'R1': 'posted', 'R2': 'reversal'}} | {'balance': 600, 'errors': [[5, 'duplicate']], 'status': {'B': 'posted', 'C': 'voided', 'D': 'posted', 'R1': 'posted', 'R2': 'reversal'}} | Passed |
| control 5 | {'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']], 'status': {'D': 'posted', 'R1': 'posted'}} | {'balance': 1099, 'errors': [[0, 'unknown'], [2, 'duplicate'], [4, 'unknown']], 'status': {'D': 'posted', 'R1': 'posted'}} | Passed |
SHA-256 / d30e956f51cf48b84c8f29ca9406eb6a299069fd50622c36267c6a95c5f6d607
Verification & scope
A deterministic bounded teaching model with stipulated toy bookkeeping rules stated in the contract; amounts are integer cents; it makes no claim of conformance to any accounting standard or product. 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:46:24.525188+00:00.
Case digest / 17ac96ded615307d97c2b502c4c366f4911bccf0efe4542ce7ac656f4ca957df