FA-88721 / Mesh topology invariants / Open access
Tetrahedral boundary faces have mixed winding · case 01
Two of the four faces of each tet point inward in the extracted surface.
ROOT CAUSE
The faces opposite b and d are listed as (a,c,d) and (a,b,c).
VERIFIED REPAIR
Use (b,c,d),(a,d,c),(a,b,d),(a,c,b).
Unsuccessful approach: Fixing the face opposite b still leaves the face opposite d inward.
Case contract
Input: tetrahedra [a,b,c,d] (positively oriented). A tet with repeated vertices returns ["degenerate", i]. Outward faces are (b,c,d),(a,d,c),(a,b,d),(a,c,b). Faces are matched by their vertex set; a set used once is boundary (kept with its first orientation, rotated to start at its smallest vertex); used more than twice returns ["non-manifold", sorted vertices]. Output boundary faces in increasing sorted-vertex-set order.
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):
tets=x
cnt={}
first={}
for i,t in enumerate(tets):
if len(set(t))<4: return ['degenerate',i]
a,b,c,d=t
for f in ((b,c,d),(a,c,d),(a,b,d),(a,b,c)):
k=tuple(sorted(f))
cnt[k]=cnt.get(k,0)+1
if k not in first: first[k]=f
out=[]
for k in sorted(cnt):
if cnt[k]==1:
f=first[k]
m=f.index(min(f))
out.append(list(f[m:]+f[:m]))
elif cnt[k]>2: return ['non-manifold',list(k)]
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]]], [['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]]]
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 |
|---|---|---|---|
| single tet | [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]] | [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]] | Failed |
| two tets sharing a face | [[0, 1, 3], [0, 4, 1], [0, 2, 3], [0, 2, 4], [1, 2, 3], [1, 2, 4]] | [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]] | Failed |
| three tets around an edge | [[0, 2, 3], [0, 4, 2], [0, 3, 4], [1, 2, 3], [1, 4, 2], [1, 3, 4]] | [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]] | Failed |
| fin face | ['non-manifold', [0, 1, 2]] | ['non-manifold', [0, 1, 2]] | Passed |
| degenerate tet | ['degenerate', 1] | ['degenerate', 1] | Passed |
| degenerate first pair | ['degenerate', 0] | ['degenerate', 0] | Passed |
| degenerate late pair | ['degenerate', 0] | ['degenerate', 0] | Passed |
SHA-256 / 261f21171ff86a6f9473b1ebfdf355822f86108ec1050996b30b1785bc7b4b91
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
tets=x
cnt={}
first={}
for i,t in enumerate(tets):
if len(set(t))<4: return ['degenerate',i]
a,b,c,d=t
for f in ((b,c,d),(a,d,c),(a,b,d),(a,b,c)):
k=tuple(sorted(f))
cnt[k]=cnt.get(k,0)+1
if k not in first: first[k]=f
out=[]
for k in sorted(cnt):
if cnt[k]==1:
f=first[k]
m=f.index(min(f))
out.append(list(f[m:]+f[:m]))
elif cnt[k]>2: return ['non-manifold',list(k)]
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]]], [['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]]]
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 |
|---|---|---|---|
| single tet | [[0, 1, 2], [0, 1, 3], [0, 3, 2], [1, 2, 3]] | [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]] | Failed |
| two tets sharing a face | [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]] | [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]] | Passed |
| three tets around an edge | [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]] | [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]] | Passed |
| fin face | ['non-manifold', [0, 1, 2]] | ['non-manifold', [0, 1, 2]] | Passed |
| degenerate tet | ['degenerate', 1] | ['degenerate', 1] | Passed |
| degenerate first pair | ['degenerate', 0] | ['degenerate', 0] | Passed |
| degenerate late pair | ['degenerate', 0] | ['degenerate', 0] | Passed |
SHA-256 / 4b9849e9057ff8e6cd35adefadb885e977f1089baf076989824b93a02861f942
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
tets=x
cnt={}
first={}
for i,t in enumerate(tets):
if len(set(t))<4: return ['degenerate',i]
a,b,c,d=t
for f in ((b,c,d),(a,d,c),(a,b,d),(a,c,b)):
k=tuple(sorted(f))
cnt[k]=cnt.get(k,0)+1
if k not in first: first[k]=f
out=[]
for k in sorted(cnt):
if cnt[k]==1:
f=first[k]
m=f.index(min(f))
out.append(list(f[m:]+f[:m]))
elif cnt[k]>2: return ['non-manifold',list(k)]
return out
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]]], [['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['two tets sharing a face', [[[0, 1, 2, 3], [1, 0, 2, 4]]], [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['three tets around an edge', [[[0, 1, 2, 3], [0, 1, 3, 4], [0, 1, 4, 2]]], [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]]], ['fin face', [[[0, 1, 2, 3], [1, 0, 2, 4], [0, 1, 2, 5]]], ['non-manifold', [0, 1, 2]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]]], [['single tet', [[[0, 1, 2, 3]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['degenerate tet', [[[0, 1, 2, 3], [4, 5, 5, 6]]], ['degenerate', 1]], ['degenerate first pair', [[[2, 2, 3, 4]]], ['degenerate', 0]], ['degenerate late pair', [[[0, 1, 2, 2]]], ['degenerate', 0]], ['rotated labels', [[[3, 1, 0, 2]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]]], ['large labels', [[[10, 7, 9, 8], [7, 10, 9, 11]]], [[7, 9, 8], [7, 8, 10], [7, 11, 9], [7, 10, 11], [8, 9, 10], [9, 11, 10]]], ['two separate tets', [[[0, 1, 2, 3], [4, 5, 6, 7]]], [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3], [4, 6, 5], [4, 5, 7], [4, 7, 6], [5, 6, 7]]]]]
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 |
|---|---|---|---|
| single tet | [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]] | [[0, 2, 1], [0, 1, 3], [0, 3, 2], [1, 2, 3]] | Passed |
| two tets sharing a face | [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]] | [[0, 1, 3], [0, 4, 1], [0, 3, 2], [0, 2, 4], [1, 2, 3], [1, 4, 2]] | Passed |
| three tets around an edge | [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]] | [[0, 3, 2], [0, 2, 4], [0, 4, 3], [1, 2, 3], [1, 4, 2], [1, 3, 4]] | Passed |
| fin face | ['non-manifold', [0, 1, 2]] | ['non-manifold', [0, 1, 2]] | Passed |
| degenerate tet | ['degenerate', 1] | ['degenerate', 1] | Passed |
| degenerate first pair | ['degenerate', 0] | ['degenerate', 0] | Passed |
| degenerate late pair | ['degenerate', 0] | ['degenerate', 0] | Passed |
SHA-256 / 874ba7c87e89b56feb20a3e599b8fbd80ca711f703ce1cb7808c509bb1b39059
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.770232+00:00.
Case digest / 252dee623fc93ddcfa39604a84680e0c1f1a30105ad337659836d59bac0bea9c