FAILURE MAP
← Case archive

FA-88636 / Mesh topology invariants / Open access

Edge flip emits triangles with reversed winding · case 01

After a flip both new triangles face inward, breaking orientation consistency.

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

ROOT CAUSE

The replacement triangles are written [c,d,a] and [d,c,b].

VERIFIED REPAIR

Write [c,a,d] and [d,b,c] to keep the quad orientation.

Unsuccessful approach: Correcting only the second triangle leaves the first reversed.

Case contract

Input [faces, a, b] for oriented triangles. The flip needs a triangle holding half-edge a->b (apex c) and one holding b->a (apex d), else "boundary"; exactly two faces may contain both a and b, else "non-manifold"; c==d is "degenerate"; an existing undirected edge c-d is "edge-exists". Otherwise replace the first triangle in place by [c,a,d] and the second by [d,b,c] and return the face list.

Why this case matters

Mesh processing pipelines (remeshing, export, simulation, printing) trust these topological counts and adjacency answers; a wrong invariant silently accepts broken meshes or rejects valid ones.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    faces,a,b=x
    fs=[list(f) for f in faces]
    t1=t2=None
    for i,f in enumerate(fs):
        for j in range(3):
            if f[j]==a and f[(j+1)%3]==b: t1=(i,f[(j+2)%3])
            if f[j]==b and f[(j+1)%3]==a: t2=(i,f[(j+2)%3])
    if t1 is None or t2 is None: return 'boundary'
    cnt=sum(1 for f in fs if a in f and b in f)
    if cnt!=2: return 'non-manifold'
    c,d=t1[1],t2[1]
    if c==d: return 'degenerate'
    for f in fs:
        for j in range(3):
            if {f[j],f[(j+1)%3]}=={c,d}: return 'edge-exists'
    fs[t1[0]]=[c,d,a]
    fs[t2[0]]=[d,c,b]
    return fs
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['rim edge', [[[[0, 1, 2], [2, 1, 3]], 0, 1]], 'boundary'], ['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['book spine', [[[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]], 0, 1]], 'non-manifold']], [['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['book spine', [[[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]], 0, 1]], 'non-manifold'], ['folded pair', [[[[0, 1, 2], [1, 0, 2]], 0, 1]], 'degenerate'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['grid interior edge', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 1, 4]], [[0, 1, 5], [0, 4, 3], [1, 2, 5], [5, 4, 0]]]], [['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['folded pair', [[[[0, 1, 2], [1, 0, 2]], 0, 1]], 'degenerate'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['grid interior edge', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 1, 4]], [[0, 1, 5], [0, 4, 3], [1, 2, 5], [5, 4, 0]]], ['fan spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0, 3]], [[0, 1, 2], [2, 3, 4], [4, 0, 2]]], ['rotated storage', [[[[2, 0, 1], [3, 1, 0], [2, 3, 4]], 0, 1]], 'edge-exists'], ['diagonal closing edge', [[[[0, 1, 2], [1, 0, 3], [3, 4, 2]], 0, 1]], 'edge-exists']], [['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['fan spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0, 3]], [[0, 1, 2], [2, 3, 4], [4, 0, 2]]], ['rotated storage', [[[[2, 0, 1], [3, 1, 0], [2, 3, 4]], 0, 1]], 'edge-exists'], ['diagonal closing edge', [[[[0, 1, 2], [1, 0, 3], [3, 4, 2]], 0, 1]], 'edge-exists'], ['diagonal stored reversed', [[[[0, 1, 2], [1, 0, 3], [3, 2, 4]], 0, 1]], 'edge-exists']], [['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['rim edge', [[[[0, 1, 2], [2, 1, 3]], 0, 1]], 'boundary'], ['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['diagonal stored reversed', [[[[0, 1, 2], [1, 0, 3], [3, 2, 4]], 0, 1]], 'edge-exists']]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), 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 fixtureActualExpectedOutcome
square diagonal[[0, 3, 1], [3, 0, 2]][[0, 1, 3], [3, 2, 0]]Failed
square diagonal reversed[[0, 3, 1], [3, 0, 2]][[0, 1, 3], [3, 2, 0]]Failed
rim edgeboundaryboundaryPassed
disk spoke[[1, 3, 2], [3, 1, 0], [0, 3, 4], [0, 4, 5], [0, 5, 1]][[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]Failed
tetrahedron edgeedge-existsedge-existsPassed
octahedron edge[[2, 4, 0], [0, 2, 3], [0, 3, 4], [4, 2, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]][[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]Failed
book spinenon-manifoldnon-manifoldPassed

SHA-256 / 0a7bb0aca78e2567b889bb9176126c20795a083d65e66d2543a3672b68ea7416

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    faces,a,b=x
    fs=[list(f) for f in faces]
    t1=t2=None
    for i,f in enumerate(fs):
        for j in range(3):
            if f[j]==a and f[(j+1)%3]==b: t1=(i,f[(j+2)%3])
            if f[j]==b and f[(j+1)%3]==a: t2=(i,f[(j+2)%3])
    if t1 is None or t2 is None: return 'boundary'
    cnt=sum(1 for f in fs if a in f and b in f)
    if cnt!=2: return 'non-manifold'
    c,d=t1[1],t2[1]
    if c==d: return 'degenerate'
    for f in fs:
        for j in range(3):
            if {f[j],f[(j+1)%3]}=={c,d}: return 'edge-exists'
    fs[t1[0]]=[c,d,a]
    fs[t2[0]]=[d,b,c]
    return fs
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['rim edge', [[[[0, 1, 2], [2, 1, 3]], 0, 1]], 'boundary'], ['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['book spine', [[[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]], 0, 1]], 'non-manifold']], [['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['book spine', [[[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]], 0, 1]], 'non-manifold'], ['folded pair', [[[[0, 1, 2], [1, 0, 2]], 0, 1]], 'degenerate'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['grid interior edge', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 1, 4]], [[0, 1, 5], [0, 4, 3], [1, 2, 5], [5, 4, 0]]]], [['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['folded pair', [[[[0, 1, 2], [1, 0, 2]], 0, 1]], 'degenerate'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['grid interior edge', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 1, 4]], [[0, 1, 5], [0, 4, 3], [1, 2, 5], [5, 4, 0]]], ['fan spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0, 3]], [[0, 1, 2], [2, 3, 4], [4, 0, 2]]], ['rotated storage', [[[[2, 0, 1], [3, 1, 0], [2, 3, 4]], 0, 1]], 'edge-exists'], ['diagonal closing edge', [[[[0, 1, 2], [1, 0, 3], [3, 4, 2]], 0, 1]], 'edge-exists']], [['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['fan spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0, 3]], [[0, 1, 2], [2, 3, 4], [4, 0, 2]]], ['rotated storage', [[[[2, 0, 1], [3, 1, 0], [2, 3, 4]], 0, 1]], 'edge-exists'], ['diagonal closing edge', [[[[0, 1, 2], [1, 0, 3], [3, 4, 2]], 0, 1]], 'edge-exists'], ['diagonal stored reversed', [[[[0, 1, 2], [1, 0, 3], [3, 2, 4]], 0, 1]], 'edge-exists']], [['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['rim edge', [[[[0, 1, 2], [2, 1, 3]], 0, 1]], 'boundary'], ['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['diagonal stored reversed', [[[[0, 1, 2], [1, 0, 3], [3, 2, 4]], 0, 1]], 'edge-exists']]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), 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 fixtureActualExpectedOutcome
square diagonal[[0, 3, 1], [3, 2, 0]][[0, 1, 3], [3, 2, 0]]Failed
square diagonal reversed[[0, 1, 3], [3, 0, 2]][[0, 1, 3], [3, 2, 0]]Failed
rim edgeboundaryboundaryPassed
disk spoke[[1, 2, 3], [3, 1, 0], [0, 3, 4], [0, 4, 5], [0, 5, 1]][[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]Failed
tetrahedron edgeedge-existsedge-existsPassed
octahedron edge[[2, 4, 0], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]][[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]Failed
book spinenon-manifoldnon-manifoldPassed

SHA-256 / 74da99cc3956ab192af75163ba2b8d2064bbac686b602578d39ddead68bc1043

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    faces,a,b=x
    fs=[list(f) for f in faces]
    t1=t2=None
    for i,f in enumerate(fs):
        for j in range(3):
            if f[j]==a and f[(j+1)%3]==b: t1=(i,f[(j+2)%3])
            if f[j]==b and f[(j+1)%3]==a: t2=(i,f[(j+2)%3])
    if t1 is None or t2 is None: return 'boundary'
    cnt=sum(1 for f in fs if a in f and b in f)
    if cnt!=2: return 'non-manifold'
    c,d=t1[1],t2[1]
    if c==d: return 'degenerate'
    for f in fs:
        for j in range(3):
            if {f[j],f[(j+1)%3]}=={c,d}: return 'edge-exists'
    fs[t1[0]]=[c,a,d]
    fs[t2[0]]=[d,b,c]
    return fs
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['rim edge', [[[[0, 1, 2], [2, 1, 3]], 0, 1]], 'boundary'], ['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['book spine', [[[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]], 0, 1]], 'non-manifold']], [['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['book spine', [[[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]], 0, 1]], 'non-manifold'], ['folded pair', [[[[0, 1, 2], [1, 0, 2]], 0, 1]], 'degenerate'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['grid interior edge', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 1, 4]], [[0, 1, 5], [0, 4, 3], [1, 2, 5], [5, 4, 0]]]], [['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['folded pair', [[[[0, 1, 2], [1, 0, 2]], 0, 1]], 'degenerate'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['grid interior edge', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 1, 4]], [[0, 1, 5], [0, 4, 3], [1, 2, 5], [5, 4, 0]]], ['fan spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0, 3]], [[0, 1, 2], [2, 3, 4], [4, 0, 2]]], ['rotated storage', [[[[2, 0, 1], [3, 1, 0], [2, 3, 4]], 0, 1]], 'edge-exists'], ['diagonal closing edge', [[[[0, 1, 2], [1, 0, 3], [3, 4, 2]], 0, 1]], 'edge-exists']], [['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['octahedron edge', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 0, 1]], [[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], ['fan spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0, 3]], [[0, 1, 2], [2, 3, 4], [4, 0, 2]]], ['rotated storage', [[[[2, 0, 1], [3, 1, 0], [2, 3, 4]], 0, 1]], 'edge-exists'], ['diagonal closing edge', [[[[0, 1, 2], [1, 0, 3], [3, 4, 2]], 0, 1]], 'edge-exists'], ['diagonal stored reversed', [[[[0, 1, 2], [1, 0, 3], [3, 2, 4]], 0, 1]], 'edge-exists']], [['square diagonal', [[[[0, 1, 2], [2, 1, 3]], 1, 2]], [[0, 1, 3], [3, 2, 0]]], ['square diagonal reversed', [[[[0, 1, 2], [2, 1, 3]], 2, 1]], [[0, 1, 3], [3, 2, 0]]], ['rim edge', [[[[0, 1, 2], [2, 1, 3]], 0, 1]], 'boundary'], ['disk spoke', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0, 2]], [[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], ['tetrahedron edge', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 0, 1]], 'edge-exists'], ['grid diagonal', [[[[0, 1, 4], [0, 4, 3], [1, 2, 5], [1, 5, 4]], 0, 4]], [[1, 4, 3], [3, 0, 1], [1, 2, 5], [1, 5, 4]]], ['diagonal stored reversed', [[[[0, 1, 2], [1, 0, 3], [3, 2, 4]], 0, 1]], 'edge-exists']]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), 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 fixtureActualExpectedOutcome
square diagonal[[0, 1, 3], [3, 2, 0]][[0, 1, 3], [3, 2, 0]]Passed
square diagonal reversed[[0, 1, 3], [3, 2, 0]][[0, 1, 3], [3, 2, 0]]Passed
rim edgeboundaryboundaryPassed
disk spoke[[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]][[1, 2, 3], [3, 0, 1], [0, 3, 4], [0, 4, 5], [0, 5, 1]]Passed
tetrahedron edgeedge-existsedge-existsPassed
octahedron edge[[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]][[2, 0, 4], [0, 2, 3], [0, 3, 4], [4, 1, 2], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]Passed
book spinenon-manifoldnon-manifoldPassed

SHA-256 / 421cb658855d5a1d9d63c299a253a251fed74dec2d5b896ebf936cfd8d9b1af0

Verification & scope

Pure combinatorial teaching model over integer face lists with a stipulated contract; no geometry kernel or file format is implied. 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:51:10.077112+00:00.

Case digest / 2ff449170c1157b5ccc221e3a635b2e89255c283e5237d6c10a114bf7849a098