FAILURE MAP
← Case archive

FA-256 / Runtime and resources / Open access

Cancellation leaves earlier acquired resources open · case 01

Cleanup is skipped after partial acquisition or stops when the first resource cleanup reports failure.

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

ROOT CAUSE

Unwinding follows only successful completion and lets one cleanup failure suppress the rest.

VERIFIED REPAIR

Attempt cleanup of every acquired resource in reverse acquisition order and collect failures independently.

Unsuccessful approach: Adding a cancellation cleanup loop still leaks earlier resources if it aborts at the first cleanup failure.

Case contract

Resources have unique names. Acquire a prefix cancel_after, or all when it is None, then unwind. Every acquired resource receives one cleanup attempt in reverse order. Named simulated cleanup failures stay open; other resources close. Return [attempt order,failure names,sorted open names].

Why this case matters

Models nested resource scopes cancelled during setup and error-tolerant cleanup; failures are injected state transitions, not real file descriptors, network calls, or exception handlers.

1 / The failure

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

N = 1
observations = []
def solve(resources, cancel_after, failures):
    acquired = list(resources[:cancel_after]) if cancel_after is not None else list(resources)
    remaining, attempted, errors = set(acquired), [], []
    if cancel_after is None:
        for identity in reversed(acquired):
            attempted.append(identity)
            if identity in failures:
                errors.append(identity)
                continue
            else:
                remaining.remove(identity)
    return [attempted, errors, sorted(remaining)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
resources = ['r'+str(i) for i in range(N+2)]
check('cancellation after partial acquisition', solve(resources, N, []), [list(reversed(resources[:N])), [], []])
check('normal completion also cleans', solve(resources, None, []), [list(reversed(resources)), [], []])
check('one failure does not suppress rest', solve(resources, None, [resources[-1]]), [list(reversed(resources)), [resources[-1]], [resources[-1]]])
check('cancel before first acquisition', solve(resources, 0, []), [[], [], []])
check('nothing acquired', solve([], None, []), [[], [], []])
check('multiple failures collected', solve(resources, None, [resources[0], resources[-1]]), [list(reversed(resources)), [resources[-1], resources[0]], sorted([resources[0], resources[-1]])])
check('unacquired failure irrelevant', solve(resources, N, [resources[-1]]), [list(reversed(resources[:N])), [], []])
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
cancellation after partial acquisition[[], [], ['r0']][['r0'], [], []]Failed
normal completion also cleans[['r2', 'r1', 'r0'], [], []][['r2', 'r1', 'r0'], [], []]Passed
one failure does not suppress rest[['r2', 'r1', 'r0'], ['r2'], ['r2']][['r2', 'r1', 'r0'], ['r2'], ['r2']]Passed
cancel before first acquisition[[], [], []][[], [], []]Passed
nothing acquired[[], [], []][[], [], []]Passed
multiple failures collected[['r2', 'r1', 'r0'], ['r2', 'r0'], ['r0', 'r2']][['r2', 'r1', 'r0'], ['r2', 'r0'], ['r0', 'r2']]Passed
unacquired failure irrelevant[[], [], ['r0']][['r0'], [], []]Failed

SHA-256 / dffd9b412db79ff8f088032b698c1884370229e6e790aa43e7d27a134ab26310

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(resources, cancel_after, failures):
    acquired = list(resources[:cancel_after]) if cancel_after is not None else list(resources)
    remaining, attempted, errors = set(acquired), [], []
    if True:
        for identity in reversed(acquired):
            attempted.append(identity)
            if identity in failures:
                errors.append(identity)
                break
            else:
                remaining.remove(identity)
    return [attempted, errors, sorted(remaining)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
resources = ['r'+str(i) for i in range(N+2)]
check('cancellation after partial acquisition', solve(resources, N, []), [list(reversed(resources[:N])), [], []])
check('normal completion also cleans', solve(resources, None, []), [list(reversed(resources)), [], []])
check('one failure does not suppress rest', solve(resources, None, [resources[-1]]), [list(reversed(resources)), [resources[-1]], [resources[-1]]])
check('cancel before first acquisition', solve(resources, 0, []), [[], [], []])
check('nothing acquired', solve([], None, []), [[], [], []])
check('multiple failures collected', solve(resources, None, [resources[0], resources[-1]]), [list(reversed(resources)), [resources[-1], resources[0]], sorted([resources[0], resources[-1]])])
check('unacquired failure irrelevant', solve(resources, N, [resources[-1]]), [list(reversed(resources[:N])), [], []])
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
cancellation after partial acquisition[['r0'], [], []][['r0'], [], []]Passed
normal completion also cleans[['r2', 'r1', 'r0'], [], []][['r2', 'r1', 'r0'], [], []]Passed
one failure does not suppress rest[['r2'], ['r2'], ['r0', 'r1', 'r2']][['r2', 'r1', 'r0'], ['r2'], ['r2']]Failed
cancel before first acquisition[[], [], []][[], [], []]Passed
nothing acquired[[], [], []][[], [], []]Passed
multiple failures collected[['r2'], ['r2'], ['r0', 'r1', 'r2']][['r2', 'r1', 'r0'], ['r2', 'r0'], ['r0', 'r2']]Failed
unacquired failure irrelevant[['r0'], [], []][['r0'], [], []]Passed

SHA-256 / e6ad9d3dbf83a67c5927a35aa0dde87305f592737a768f545d8f84f9bfa983b4

3 / The verified repair

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

N = 1
observations = []
def solve(resources, cancel_after, failures):
    acquired = list(resources[:cancel_after]) if cancel_after is not None else list(resources)
    remaining, attempted, errors = set(acquired), [], []
    if True:
        for identity in reversed(acquired):
            attempted.append(identity)
            if identity in failures:
                errors.append(identity)
                continue
            else:
                remaining.remove(identity)
    return [attempted, errors, sorted(remaining)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
resources = ['r'+str(i) for i in range(N+2)]
check('cancellation after partial acquisition', solve(resources, N, []), [list(reversed(resources[:N])), [], []])
check('normal completion also cleans', solve(resources, None, []), [list(reversed(resources)), [], []])
check('one failure does not suppress rest', solve(resources, None, [resources[-1]]), [list(reversed(resources)), [resources[-1]], [resources[-1]]])
check('cancel before first acquisition', solve(resources, 0, []), [[], [], []])
check('nothing acquired', solve([], None, []), [[], [], []])
check('multiple failures collected', solve(resources, None, [resources[0], resources[-1]]), [list(reversed(resources)), [resources[-1], resources[0]], sorted([resources[0], resources[-1]])])
check('unacquired failure irrelevant', solve(resources, N, [resources[-1]]), [list(reversed(resources[:N])), [], []])
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
cancellation after partial acquisition[['r0'], [], []][['r0'], [], []]Passed
normal completion also cleans[['r2', 'r1', 'r0'], [], []][['r2', 'r1', 'r0'], [], []]Passed
one failure does not suppress rest[['r2', 'r1', 'r0'], ['r2'], ['r2']][['r2', 'r1', 'r0'], ['r2'], ['r2']]Passed
cancel before first acquisition[[], [], []][[], [], []]Passed
nothing acquired[[], [], []][[], [], []]Passed
multiple failures collected[['r2', 'r1', 'r0'], ['r2', 'r0'], ['r0', 'r2']][['r2', 'r1', 'r0'], ['r2', 'r0'], ['r0', 'r2']]Passed
unacquired failure irrelevant[['r0'], [], []][['r0'], [], []]Passed

SHA-256 / f44af2f7a601468e81031623f28512490ee7ca7175d4ff4d5541655e68011348

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

Case digest / 732d73c1e5eda4f640c525102c964257002b9265e646faa26f6bf88ea2b514c7