FA-88376 / Mesh topology invariants / Open access
Inconsistent orientation outranks non-manifold edges · case 01
A mesh with both fins and flipped faces is reported as merely inconsistent.
ROOT CAUSE
The verdict chain tests inconsistency before non-manifoldness.
VERIFIED REPAIR
Report non-manifold first whenever any edge has more than two uses.
Unsuccessful approach: Choosing whichever count is larger ignores the fixed precedence.
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
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 inc: v='non-orientable-or-inconsistent'
elif nm: v='non-manifold'
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']], ['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']]], [['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']], ['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']], ['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']], ['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']], ['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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 |
| book and flipped pair | [10, 1, 1, 1, 'non-orientable-or-inconsistent'] | [10, 1, 1, 1, 'non-manifold'] | Failed |
SHA-256 / ae62dd29062b75ba713122746401e05f5a7da7ce50f41c9b47d711e7f0161934
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 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>inc: 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']], ['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']]], [['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']], ['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']], ['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']], ['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']], ['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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 |
| book and flipped pair | [10, 1, 1, 1, 'non-orientable-or-inconsistent'] | [10, 1, 1, 1, 'non-manifold'] | Failed |
SHA-256 / 12e298a7d55493070c2460997cfeed5b66747d2449357c454c39a514cdb514a9
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']], ['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']]], [['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']], ['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']], ['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']], ['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']], ['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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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 |
| book and flipped pair | [10, 1, 1, 1, 'non-manifold'] | [10, 1, 1, 1, 'non-manifold'] | Passed |
SHA-256 / 991b48321047d7e59724657bc3b1cec4c4c47a02ac03e641a771b17d19c76cdf
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.528056+00:00.
Case digest / ec9b430f345b9f50a9941cdb1b979078e1f6794d36f4b3d471f08546d99d125d