FAILURE MAP
← Case archive

FA-12476 / Molecular graph representation / Open access

Bond reversal leaves endpoint-specific stereo ligands attached to wrong atoms · case 01

Bond reversal leaves endpoint-specific stereo ligands attached to wrong atoms.

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

ROOT CAUSE

Endpoint sorting leaves left/right ligand references in their original slots.

VERIFIED REPAIR

Implement the explicit toy representation contract: A double bond record [a,b,left_ligand,right_ligand] uses endpoint-relative ligand anchors. Canonicalize a<=b, swapping ligand anchor slots if and only if endpoints reverse.

Unsuccessful approach: Swapping ligand slots on every bond damages already canonical bonds.

Case contract

A double bond record [a,b,left_ligand,right_ligand] uses endpoint-relative ligand anchors. Canonicalize a<=b, swapping ligand anchor slots if and only if endpoints reverse.

Why this case matters

Controlled molecular graph interchange model; tests isolate atom or bond representation errors without claiming chemical validity or production toolkit equivalence.

1 / The failure

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

N = 1
observations = []
def solve(a, b, left, right):
    return [min(a,b),max(a,b),left,right]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('reverse anchors', solve(N+1,N,30+N,40+N), [N,N+1,40+N,30+N])
check('forward anchors', solve(N,N+1,30+N,40+N), [N,N+1,30+N,40+N])
check('implicit left', solve(N+1,N,None,40+N), [N,N+1,40+N,None])
check('implicit right', solve(N,N+1,30+N,None), [N,N+1,30+N,None])
check('both implicit', solve(N+1,N,None,None), [N,N+1,None,None])
check('zero ligand ID', solve(N,N+1,0,40+N), [N,N+1,0,40+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
reverse anchors[1, 2, 31, 41][1, 2, 41, 31]Failed
forward anchors[1, 2, 31, 41][1, 2, 31, 41]Passed
implicit left[1, 2, None, 41][1, 2, 41, None]Failed
implicit right[1, 2, 31, None][1, 2, 31, None]Passed
both implicit[1, 2, None, None][1, 2, None, None]Passed
zero ligand ID[1, 2, 0, 41][1, 2, 0, 41]Passed

SHA-256 / 0445a701a2b72644680594bbe24e3ecf537e4980a231eb631f2ee1cebcbc2a25

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(a, b, left, right):
    return [min(a,b),max(a,b),right,left]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('reverse anchors', solve(N+1,N,30+N,40+N), [N,N+1,40+N,30+N])
check('forward anchors', solve(N,N+1,30+N,40+N), [N,N+1,30+N,40+N])
check('implicit left', solve(N+1,N,None,40+N), [N,N+1,40+N,None])
check('implicit right', solve(N,N+1,30+N,None), [N,N+1,30+N,None])
check('both implicit', solve(N+1,N,None,None), [N,N+1,None,None])
check('zero ligand ID', solve(N,N+1,0,40+N), [N,N+1,0,40+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
reverse anchors[1, 2, 41, 31][1, 2, 41, 31]Passed
forward anchors[1, 2, 41, 31][1, 2, 31, 41]Failed
implicit left[1, 2, 41, None][1, 2, 41, None]Passed
implicit right[1, 2, None, 31][1, 2, 31, None]Failed
both implicit[1, 2, None, None][1, 2, None, None]Passed
zero ligand ID[1, 2, 41, 0][1, 2, 0, 41]Failed

SHA-256 / eec57690e9d0a2ba2fef524325004ac60928e5e026a29a0d4b766081343d5ea4

3 / The verified repair

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

N = 1
observations = []
def solve(a, b, left, right):
    return [a,b,left,right] if a <= b else [b,a,right,left]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('reverse anchors', solve(N+1,N,30+N,40+N), [N,N+1,40+N,30+N])
check('forward anchors', solve(N,N+1,30+N,40+N), [N,N+1,30+N,40+N])
check('implicit left', solve(N+1,N,None,40+N), [N,N+1,40+N,None])
check('implicit right', solve(N,N+1,30+N,None), [N,N+1,30+N,None])
check('both implicit', solve(N+1,N,None,None), [N,N+1,None,None])
check('zero ligand ID', solve(N,N+1,0,40+N), [N,N+1,0,40+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
reverse anchors[1, 2, 41, 31][1, 2, 41, 31]Passed
forward anchors[1, 2, 31, 41][1, 2, 31, 41]Passed
implicit left[1, 2, 41, None][1, 2, 41, None]Passed
implicit right[1, 2, 31, None][1, 2, 31, None]Passed
both implicit[1, 2, None, None][1, 2, None, None]Passed
zero ligand ID[1, 2, 0, 41][1, 2, 0, 41]Passed

SHA-256 / ab07c3b7867180f9ec6ab777e903606e657b6ce972995b10e2b8ddb24f6a93a5

Verification & scope

Toy representation only; no valence inference, chemical sanitization, synthesis, or real molecular identity determination. 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:38:57.279485+00:00.

Case digest / 01f1c75f678c56b3b1426e8ddb09388dfdf2afd718099171609decab92e8e977