FAILURE MAP
← Case archive

FA-88391 / Mesh topology invariants / Open access

An empty face list is reported as a closed oriented surface · case 01

Empty meshes pass watertightness checks.

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

ROOT CAUSE

The empty-input guard is missing, so zero counts fall through to the last verdict.

VERIFIED REPAIR

Return "empty" for an empty face list.

Unsuccessful approach: Testing for None misses the empty list.

Case contract

Input: polygon faces. Empty input returns "empty". Consecutive repeated indices form no edge (skip that pair only). Undirected edges used once are boundary, twice interior, more non-manifold; an interior edge whose two uses have the same direction is inconsistent. Verdict precedence: non-manifold, then "non-orientable-or-inconsistent", then "open-oriented" (boundary present), else "closed-oriented". Return [boundary, interior, nonmanifold, inconsistent, verdict].

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=x
    uses={}
    for f in faces:
        n=len(f)
        for i in range(n):
            a,b=f[i],f[(i+1)%n]
            if a==b: continue
            uses.setdefault((min(a,b),max(a,b)),[]).append((a,b))
    bd=it=nm=inc=0
    for k in sorted(uses):
        u=uses[k]
        if len(u)==1: bd+=1
        elif len(u)==2:
            it+=1
            if u[0]==u[1]: inc+=1
        else: nm+=1
    if nm: v='non-manifold'
    elif inc: v='non-orientable-or-inconsistent'
    elif bd: v='open-oriented'
    else: v='closed-oriented'
    return [bd,it,nm,inc,v]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['disk', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [5, 5, 0, 0, 'open-oriented']], ['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['flipped pair', [[[0, 1, 2], [0, 1, 3]]], [4, 1, 0, 1, 'non-orientable-or-inconsistent']], ['empty', [[]], 'empty']], [['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['flipped pair', [[[0, 1, 2], [0, 1, 3]]], [4, 1, 0, 1, 'non-orientable-or-inconsistent']], ['bowtie', [[[0, 1, 2], [0, 3, 4]]], [6, 0, 0, 0, 'open-oriented']], ['empty', [[]], 'empty'], ['repeated corner', [[[0, 1, 1, 2], [2, 1, 3]]], [4, 1, 0, 0, 'open-oriented']], ['book and flipped pair', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [5, 6, 7], [5, 6, 8]]], [10, 1, 1, 1, 'non-manifold']]], [['bowtie', [[[0, 1, 2], [0, 3, 4]]], [6, 0, 0, 0, 'open-oriented']], ['empty', [[]], 'empty'], ['repeated corner', [[[0, 1, 1, 2], [2, 1, 3]]], [4, 1, 0, 0, 'open-oriented']], ['book and flipped pair', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [5, 6, 7], [5, 6, 8]]], [10, 1, 1, 1, 'non-manifold']], ['four sheets', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]]], [8, 0, 1, 0, 'non-manifold']], ['torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [0, 27, 0, 0, 'closed-oriented']], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [0, 15, 0, 10, 'non-orientable-or-inconsistent']]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['empty', [[]], 'empty'], ['four sheets', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]]], [8, 0, 1, 0, 'non-manifold']], ['torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [0, 27, 0, 0, 'closed-oriented']], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [0, 15, 0, 10, 'non-orientable-or-inconsistent']], ['repeated corner closed', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['disk', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [5, 5, 0, 0, 'open-oriented']], ['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['empty', [[]], 'empty'], ['repeated corner closed', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']]]]
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
tetrahedron[0, 6, 0, 0, 'closed-oriented'][0, 6, 0, 0, 'closed-oriented']Passed
cube[0, 12, 0, 0, 'closed-oriented'][0, 12, 0, 0, 'closed-oriented']Passed
disk[5, 5, 0, 0, 'open-oriented'][5, 5, 0, 0, 'open-oriented']Passed
mobius[6, 3, 0, 1, 'non-orientable-or-inconsistent'][6, 3, 0, 1, 'non-orientable-or-inconsistent']Passed
book[6, 0, 1, 0, 'non-manifold'][6, 0, 1, 0, 'non-manifold']Passed
flipped pair[4, 1, 0, 1, 'non-orientable-or-inconsistent'][4, 1, 0, 1, 'non-orientable-or-inconsistent']Passed
empty[0, 0, 0, 0, 'closed-oriented']emptyFailed

SHA-256 / 55d6b50da7d7f662b3016d6ebc716521c0bb65d90d5fae433827fd7314eb42c7

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=x
    if faces is None: return 'empty'
    uses={}
    for f in faces:
        n=len(f)
        for i in range(n):
            a,b=f[i],f[(i+1)%n]
            if a==b: continue
            uses.setdefault((min(a,b),max(a,b)),[]).append((a,b))
    bd=it=nm=inc=0
    for k in sorted(uses):
        u=uses[k]
        if len(u)==1: bd+=1
        elif len(u)==2:
            it+=1
            if u[0]==u[1]: inc+=1
        else: nm+=1
    if nm: v='non-manifold'
    elif inc: v='non-orientable-or-inconsistent'
    elif bd: v='open-oriented'
    else: v='closed-oriented'
    return [bd,it,nm,inc,v]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['disk', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [5, 5, 0, 0, 'open-oriented']], ['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['flipped pair', [[[0, 1, 2], [0, 1, 3]]], [4, 1, 0, 1, 'non-orientable-or-inconsistent']], ['empty', [[]], 'empty']], [['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['flipped pair', [[[0, 1, 2], [0, 1, 3]]], [4, 1, 0, 1, 'non-orientable-or-inconsistent']], ['bowtie', [[[0, 1, 2], [0, 3, 4]]], [6, 0, 0, 0, 'open-oriented']], ['empty', [[]], 'empty'], ['repeated corner', [[[0, 1, 1, 2], [2, 1, 3]]], [4, 1, 0, 0, 'open-oriented']], ['book and flipped pair', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [5, 6, 7], [5, 6, 8]]], [10, 1, 1, 1, 'non-manifold']]], [['bowtie', [[[0, 1, 2], [0, 3, 4]]], [6, 0, 0, 0, 'open-oriented']], ['empty', [[]], 'empty'], ['repeated corner', [[[0, 1, 1, 2], [2, 1, 3]]], [4, 1, 0, 0, 'open-oriented']], ['book and flipped pair', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [5, 6, 7], [5, 6, 8]]], [10, 1, 1, 1, 'non-manifold']], ['four sheets', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]]], [8, 0, 1, 0, 'non-manifold']], ['torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [0, 27, 0, 0, 'closed-oriented']], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [0, 15, 0, 10, 'non-orientable-or-inconsistent']]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['empty', [[]], 'empty'], ['four sheets', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]]], [8, 0, 1, 0, 'non-manifold']], ['torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [0, 27, 0, 0, 'closed-oriented']], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [0, 15, 0, 10, 'non-orientable-or-inconsistent']], ['repeated corner closed', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['disk', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [5, 5, 0, 0, 'open-oriented']], ['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['empty', [[]], 'empty'], ['repeated corner closed', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']]]]
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
tetrahedron[0, 6, 0, 0, 'closed-oriented'][0, 6, 0, 0, 'closed-oriented']Passed
cube[0, 12, 0, 0, 'closed-oriented'][0, 12, 0, 0, 'closed-oriented']Passed
disk[5, 5, 0, 0, 'open-oriented'][5, 5, 0, 0, 'open-oriented']Passed
mobius[6, 3, 0, 1, 'non-orientable-or-inconsistent'][6, 3, 0, 1, 'non-orientable-or-inconsistent']Passed
book[6, 0, 1, 0, 'non-manifold'][6, 0, 1, 0, 'non-manifold']Passed
flipped pair[4, 1, 0, 1, 'non-orientable-or-inconsistent'][4, 1, 0, 1, 'non-orientable-or-inconsistent']Passed
empty[0, 0, 0, 0, 'closed-oriented']emptyFailed

SHA-256 / fe66c4b4b73bd8f2f5923cc0ce98997ce6635faed40b7917c4ceb7c0f5683def

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=x
    if not faces: return 'empty'
    uses={}
    for f in faces:
        n=len(f)
        for i in range(n):
            a,b=f[i],f[(i+1)%n]
            if a==b: continue
            uses.setdefault((min(a,b),max(a,b)),[]).append((a,b))
    bd=it=nm=inc=0
    for k in sorted(uses):
        u=uses[k]
        if len(u)==1: bd+=1
        elif len(u)==2:
            it+=1
            if u[0]==u[1]: inc+=1
        else: nm+=1
    if nm: v='non-manifold'
    elif inc: v='non-orientable-or-inconsistent'
    elif bd: v='open-oriented'
    else: v='closed-oriented'
    return [bd,it,nm,inc,v]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['disk', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [5, 5, 0, 0, 'open-oriented']], ['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['flipped pair', [[[0, 1, 2], [0, 1, 3]]], [4, 1, 0, 1, 'non-orientable-or-inconsistent']], ['empty', [[]], 'empty']], [['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['flipped pair', [[[0, 1, 2], [0, 1, 3]]], [4, 1, 0, 1, 'non-orientable-or-inconsistent']], ['bowtie', [[[0, 1, 2], [0, 3, 4]]], [6, 0, 0, 0, 'open-oriented']], ['empty', [[]], 'empty'], ['repeated corner', [[[0, 1, 1, 2], [2, 1, 3]]], [4, 1, 0, 0, 'open-oriented']], ['book and flipped pair', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [5, 6, 7], [5, 6, 8]]], [10, 1, 1, 1, 'non-manifold']]], [['bowtie', [[[0, 1, 2], [0, 3, 4]]], [6, 0, 0, 0, 'open-oriented']], ['empty', [[]], 'empty'], ['repeated corner', [[[0, 1, 1, 2], [2, 1, 3]]], [4, 1, 0, 0, 'open-oriented']], ['book and flipped pair', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [5, 6, 7], [5, 6, 8]]], [10, 1, 1, 1, 'non-manifold']], ['four sheets', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]]], [8, 0, 1, 0, 'non-manifold']], ['torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [0, 27, 0, 0, 'closed-oriented']], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [0, 15, 0, 10, 'non-orientable-or-inconsistent']]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['empty', [[]], 'empty'], ['four sheets', [[[0, 1, 2], [1, 0, 3], [0, 1, 4], [1, 0, 5]]], [8, 0, 1, 0, 'non-manifold']], ['torus', [[[0, 3, 4], [0, 4, 1], [1, 4, 5], [1, 5, 2], [2, 5, 3], [2, 3, 0], [3, 6, 7], [3, 7, 4], [4, 7, 8], [4, 8, 5], [5, 8, 6], [5, 6, 3], [6, 0, 1], [6, 1, 7], [7, 1, 2], [7, 2, 8], [8, 2, 0], [8, 0, 6]]], [0, 27, 0, 0, 'closed-oriented']], ['projective plane', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [1, 2, 4], [2, 3, 5], [3, 4, 1], [4, 5, 2], [5, 1, 3]]], [0, 15, 0, 10, 'non-orientable-or-inconsistent']], ['repeated corner closed', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']], ['cube', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [0, 12, 0, 0, 'closed-oriented']], ['disk', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [5, 5, 0, 0, 'open-oriented']], ['mobius', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 3, 0, 1, 'non-orientable-or-inconsistent']], ['book', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [6, 0, 1, 0, 'non-manifold']], ['empty', [[]], 'empty'], ['repeated corner closed', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 3, 2]]], [0, 6, 0, 0, 'closed-oriented']]]]
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
tetrahedron[0, 6, 0, 0, 'closed-oriented'][0, 6, 0, 0, 'closed-oriented']Passed
cube[0, 12, 0, 0, 'closed-oriented'][0, 12, 0, 0, 'closed-oriented']Passed
disk[5, 5, 0, 0, 'open-oriented'][5, 5, 0, 0, 'open-oriented']Passed
mobius[6, 3, 0, 1, 'non-orientable-or-inconsistent'][6, 3, 0, 1, 'non-orientable-or-inconsistent']Passed
book[6, 0, 1, 0, 'non-manifold'][6, 0, 1, 0, 'non-manifold']Passed
flipped pair[4, 1, 0, 1, 'non-orientable-or-inconsistent'][4, 1, 0, 1, 'non-orientable-or-inconsistent']Passed
emptyemptyemptyPassed

SHA-256 / 09da7cc2042ccaac4f15646888776eda0a28535ceece2d0d017591c873bd6cd2

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

Case digest / cefb617008285d3de1cc4672304d2b933fd1a648fdf1a0999b6d5275b7ce1e9b