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.
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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