FAILURE MAP
← Case archive

FA-45941 / Bounded deques / Open access

Unlink leaves a successor back-link pointing to the detached node · case 01

Unlink leaves a successor back-link pointing to the detached node.

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

ROOT CAUSE

The backward adjacency is not rewired with the forward adjacency.

VERIFIED REPAIR

Restore the documented successor edge invariant in intrusive-unlink.

Unsuccessful approach: The partial repair still applies the incorrect transition to an admitted boundary or multi-element case.

Case contract

Unlink one selected node from a finite doubly linked deque with sentinel S. Nodes are keyed by identity; return forward IDs, backward IDs, removed node links, size, sentinel endpoint links and reciprocal-link validity. Every input ID is unique.

Why this case matters

Controlled bounded deque implementation model with explicit storage and lifecycle observations.

1 / The failure

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

N = 1
observations = []
def solve(x):
    ids, victim = x
    nodes = {'S': ['S','S']}
    for i, value in enumerate(ids):
        nodes[value] = [ids[i-1] if i else 'S', ids[i+1] if i+1 < len(ids) else 'S']
    if ids:
        nodes['S'] = [ids[-1],ids[0]]
    size = len(ids)
    left, right = nodes[victim]
    nodes[left][1] = right
    nodes[right][0] = victim
    nodes[victim] = [None,None]
    size -= 1
    forward = []
    current = nodes['S'][1]
    for _ in range(len(ids)+1):
        if current == 'S' or current is None: break
        forward.append(current)
        current = nodes[current][1]
    backward = []
    current = nodes['S'][0]
    for _ in range(len(ids)+1):
        if current == 'S' or current is None: break
        backward.append(current)
        current = nodes[current][0]
    valid = all(nodes[nodes[v][0]][1] == v and nodes[nodes[v][1]][0] == v for v in forward if nodes[v][0] is not None and nodes[v][1] is not None)
    return [forward,backward,nodes[victim],size,nodes['S'],valid]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('middle unlink', solve([[N,N+1,N+2],N+1]), [[N,N+2],[N+2,N],[None,None],2,[N+2,N],True])
check('head unlink', solve([[N,N+1,N+2],N]), [[N+1,N+2],[N+2,N+1],[None,None],2,[N+2,N+1],True])
check('tail unlink', solve([[N,N+1,N+2],N+2]), [[N,N+1],[N+1,N],[None,None],2,[N+1,N],True])
check('only node', solve([[N],N]), [[],[],[None,None],0,["S","S"],True])
check('pair head', solve([[N,N+1],N]), [[N+1],[N+1],[None,None],1,[N+1,N+1],True])
check('long middle', solve([[N,N+1,N+2,N+3,N+4],N+2]), [[N,N+1,N+3,N+4],[N+4,N+3,N+1,N],[None,None],4,[N+4,N],True])
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
middle unlink[[1, 3], [3, 2], [None, None], 2, [3, 1], False][[1, 3], [3, 1], [None, None], 2, [3, 1], True]Failed
head unlink[[2, 3], [3, 2, 1], [None, None], 2, [3, 2], False][[2, 3], [3, 2], [None, None], 2, [3, 2], True]Failed
tail unlink[[1, 2], [3], [None, None], 2, [3, 1], False][[1, 2], [2, 1], [None, None], 2, [2, 1], True]Failed
only node[[], [1], [None, None], 0, [1, 'S'], True][[], [], [None, None], 0, ['S', 'S'], True]Failed
pair head[[2], [2, 1], [None, None], 1, [2, 2], False][[2], [2], [None, None], 1, [2, 2], True]Failed
long middle[[1, 2, 4, 5], [5, 4, 3], [None, None], 4, [5, 1], False][[1, 2, 4, 5], [5, 4, 2, 1], [None, None], 4, [5, 1], True]Failed

SHA-256 / 97a768237953ce2e5ed02dbaec735dd916b5f10b0fa6334e08c411994ee722da

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    ids, victim = x
    nodes = {'S': ['S','S']}
    for i, value in enumerate(ids):
        nodes[value] = [ids[i-1] if i else 'S', ids[i+1] if i+1 < len(ids) else 'S']
    if ids:
        nodes['S'] = [ids[-1],ids[0]]
    size = len(ids)
    left, right = nodes[victim]
    nodes[left][1] = right
    nodes[right][0] = left if right == "S" else victim
    nodes[victim] = [None,None]
    size -= 1
    forward = []
    current = nodes['S'][1]
    for _ in range(len(ids)+1):
        if current == 'S' or current is None: break
        forward.append(current)
        current = nodes[current][1]
    backward = []
    current = nodes['S'][0]
    for _ in range(len(ids)+1):
        if current == 'S' or current is None: break
        backward.append(current)
        current = nodes[current][0]
    valid = all(nodes[nodes[v][0]][1] == v and nodes[nodes[v][1]][0] == v for v in forward if nodes[v][0] is not None and nodes[v][1] is not None)
    return [forward,backward,nodes[victim],size,nodes['S'],valid]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('middle unlink', solve([[N,N+1,N+2],N+1]), [[N,N+2],[N+2,N],[None,None],2,[N+2,N],True])
check('head unlink', solve([[N,N+1,N+2],N]), [[N+1,N+2],[N+2,N+1],[None,None],2,[N+2,N+1],True])
check('tail unlink', solve([[N,N+1,N+2],N+2]), [[N,N+1],[N+1,N],[None,None],2,[N+1,N],True])
check('only node', solve([[N],N]), [[],[],[None,None],0,["S","S"],True])
check('pair head', solve([[N,N+1],N]), [[N+1],[N+1],[None,None],1,[N+1,N+1],True])
check('long middle', solve([[N,N+1,N+2,N+3,N+4],N+2]), [[N,N+1,N+3,N+4],[N+4,N+3,N+1,N],[None,None],4,[N+4,N],True])
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
middle unlink[[1, 3], [3, 2], [None, None], 2, [3, 1], False][[1, 3], [3, 1], [None, None], 2, [3, 1], True]Failed
head unlink[[2, 3], [3, 2, 1], [None, None], 2, [3, 2], False][[2, 3], [3, 2], [None, None], 2, [3, 2], True]Failed
tail unlink[[1, 2], [2, 1], [None, None], 2, [2, 1], True][[1, 2], [2, 1], [None, None], 2, [2, 1], True]Passed
only node[[], [], [None, None], 0, ['S', 'S'], True][[], [], [None, None], 0, ['S', 'S'], True]Passed
pair head[[2], [2, 1], [None, None], 1, [2, 2], False][[2], [2], [None, None], 1, [2, 2], True]Failed
long middle[[1, 2, 4, 5], [5, 4, 3], [None, None], 4, [5, 1], False][[1, 2, 4, 5], [5, 4, 2, 1], [None, None], 4, [5, 1], True]Failed

SHA-256 / bc3e78869a10bbdde0050daef9906a0f4bcbfdf59e4807ccb1b1fd02a1773d51

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    ids, victim = x
    nodes = {'S': ['S','S']}
    for i, value in enumerate(ids):
        nodes[value] = [ids[i-1] if i else 'S', ids[i+1] if i+1 < len(ids) else 'S']
    if ids:
        nodes['S'] = [ids[-1],ids[0]]
    size = len(ids)
    left, right = nodes[victim]
    nodes[left][1] = right
    nodes[right][0] = left
    nodes[victim] = [None,None]
    size -= 1
    forward = []
    current = nodes['S'][1]
    for _ in range(len(ids)+1):
        if current == 'S' or current is None: break
        forward.append(current)
        current = nodes[current][1]
    backward = []
    current = nodes['S'][0]
    for _ in range(len(ids)+1):
        if current == 'S' or current is None: break
        backward.append(current)
        current = nodes[current][0]
    valid = all(nodes[nodes[v][0]][1] == v and nodes[nodes[v][1]][0] == v for v in forward if nodes[v][0] is not None and nodes[v][1] is not None)
    return [forward,backward,nodes[victim],size,nodes['S'],valid]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('middle unlink', solve([[N,N+1,N+2],N+1]), [[N,N+2],[N+2,N],[None,None],2,[N+2,N],True])
check('head unlink', solve([[N,N+1,N+2],N]), [[N+1,N+2],[N+2,N+1],[None,None],2,[N+2,N+1],True])
check('tail unlink', solve([[N,N+1,N+2],N+2]), [[N,N+1],[N+1,N],[None,None],2,[N+1,N],True])
check('only node', solve([[N],N]), [[],[],[None,None],0,["S","S"],True])
check('pair head', solve([[N,N+1],N]), [[N+1],[N+1],[None,None],1,[N+1,N+1],True])
check('long middle', solve([[N,N+1,N+2,N+3,N+4],N+2]), [[N,N+1,N+3,N+4],[N+4,N+3,N+1,N],[None,None],4,[N+4,N],True])
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
middle unlink[[1, 3], [3, 1], [None, None], 2, [3, 1], True][[1, 3], [3, 1], [None, None], 2, [3, 1], True]Passed
head unlink[[2, 3], [3, 2], [None, None], 2, [3, 2], True][[2, 3], [3, 2], [None, None], 2, [3, 2], True]Passed
tail unlink[[1, 2], [2, 1], [None, None], 2, [2, 1], True][[1, 2], [2, 1], [None, None], 2, [2, 1], True]Passed
only node[[], [], [None, None], 0, ['S', 'S'], True][[], [], [None, None], 0, ['S', 'S'], True]Passed
pair head[[2], [2], [None, None], 1, [2, 2], True][[2], [2], [None, None], 1, [2, 2], True]Passed
long middle[[1, 2, 4, 5], [5, 4, 2, 1], [None, None], 4, [5, 1], True][[1, 2, 4, 5], [5, 4, 2, 1], [None, None], 4, [5, 1], True]Passed

SHA-256 / 3ae9149a9b856352139003db699b56d2d0ed738050dc647ebe38200d700331f0

Verification & scope

Offline finite deterministic model; no claim of production implementation or concurrent memory-model conformance. 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:44:27.204619+00:00.

Case digest / e688d6147d09ec03ee3534a2afabd1e426281ca59145e00635581108157a2d43