FAILURE MAP
← Case archive

FA-88341 / Mesh topology invariants / Open access

Euler count stores each shared edge once per direction · case 01

Closed meshes report twice as many edges and a strongly negative Euler characteristic.

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

ROOT CAUSE

Edges are keyed by the directed pair (a,b), so the two half-edges of a shared edge become two edges.

VERIFIED REPAIR

Key edges by (min, max) of their endpoints.

Unsuccessful approach: Canonicalising only triangle faces still double counts every edge shared by polygons.

Case contract

Input: list of polygon faces (vertex index lists). V counts referenced vertices, E distinct undirected edges (closing edge included), F faces, chi=V-E+F, C connected components (via edges), B boundary loops = components of the graph of edges used by exactly one face. Return [V,E,F,chi,C,B,genus] with genus=(2C-chi-B)/2 or null when that numerator is odd (non-orientable signal).

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
    edges={}
    for f in faces:
        n=len(f)
        for i in range(n):
            a,b=f[i],f[(i+1)%n]
            k=(a,b)
            edges[k]=edges.get(k,0)+1
    verts=sorted({v for f in faces for v in f})
    V=len(verts)
    E=len(edges)
    Fc=len(faces)
    chi=V-E+Fc
    parent={v:v for v in verts}
    def find(v):
        while parent[v]!=v:
            v=parent[v]
        return v
    for a,b in edges:
        ra,rb=find(a),find(b)
        if ra!=rb: parent[ra]=rb
    comps=len({find(v) for v in verts})
    bpar={}
    def bfind(v):
        while bpar[v]!=v:
            v=bpar[v]
        return v
    for (a,b),c in edges.items():
        if c==1:
            bpar.setdefault(a,a)
            bpar.setdefault(b,b)
            ra,rb=bfind(a),bfind(b)
            if ra!=rb: bpar[ra]=rb
    loops=len({bfind(v) for v in bpar})
    g=2*comps-chi-loops
    genus=None if g%2 else g//2
    return [V,E,Fc,chi,comps,loops,genus]
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]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['triangle 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]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]]], [['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['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]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]]], [['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['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]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]]], [['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle 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]]], [9, 27, 18, 0, 1, 0, 1]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]], ['tetrahedra sharing a face', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [0, 1, 4], [1, 2, 4], [0, 4, 2]]], [5, 9, 7, 3, 1, 0, None]]]]
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[4, 12, 4, -4, 1, 1, None][4, 6, 4, 2, 1, 0, 0]Failed
cube quads[8, 24, 6, -10, 1, 1, None][8, 12, 6, 2, 1, 0, 0]Failed
octahedron[6, 24, 8, -10, 1, 1, None][6, 12, 8, 2, 1, 0, 0]Failed
quad torus[9, 36, 9, -18, 1, 1, None][9, 18, 9, 0, 1, 0, 1]Failed
triangle torus[9, 54, 18, -27, 1, 1, 14][9, 27, 18, 0, 1, 0, 1]Failed
disk fan[6, 15, 5, -4, 1, 1, None][6, 10, 5, 1, 1, 1, 0]Failed
quad annulus[6, 12, 3, -3, 1, 1, 2][6, 9, 3, 0, 1, 2, 0]Failed

SHA-256 / 44a4a5804e96ae0f3e8d4737ce0f2f1f1e8f815770f36fd7b9e850ddc53187f2

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
    edges={}
    for f in faces:
        n=len(f)
        for i in range(n):
            a,b=f[i],f[(i+1)%n]
            k=(min(a,b),max(a,b)) if n==3 else (a,b)
            edges[k]=edges.get(k,0)+1
    verts=sorted({v for f in faces for v in f})
    V=len(verts)
    E=len(edges)
    Fc=len(faces)
    chi=V-E+Fc
    parent={v:v for v in verts}
    def find(v):
        while parent[v]!=v:
            v=parent[v]
        return v
    for a,b in edges:
        ra,rb=find(a),find(b)
        if ra!=rb: parent[ra]=rb
    comps=len({find(v) for v in verts})
    bpar={}
    def bfind(v):
        while bpar[v]!=v:
            v=bpar[v]
        return v
    for (a,b),c in edges.items():
        if c==1:
            bpar.setdefault(a,a)
            bpar.setdefault(b,b)
            ra,rb=bfind(a),bfind(b)
            if ra!=rb: bpar[ra]=rb
    loops=len({bfind(v) for v in bpar})
    g=2*comps-chi-loops
    genus=None if g%2 else g//2
    return [V,E,Fc,chi,comps,loops,genus]
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]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['triangle 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]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]]], [['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['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]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]]], [['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['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]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]]], [['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle 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]]], [9, 27, 18, 0, 1, 0, 1]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]], ['tetrahedra sharing a face', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [0, 1, 4], [1, 2, 4], [0, 4, 2]]], [5, 9, 7, 3, 1, 0, None]]]]
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[4, 6, 4, 2, 1, 0, 0][4, 6, 4, 2, 1, 0, 0]Passed
cube quads[8, 24, 6, -10, 1, 1, None][8, 12, 6, 2, 1, 0, 0]Failed
octahedron[6, 12, 8, 2, 1, 0, 0][6, 12, 8, 2, 1, 0, 0]Passed
quad torus[9, 36, 9, -18, 1, 1, None][9, 18, 9, 0, 1, 0, 1]Failed
triangle torus[9, 27, 18, 0, 1, 0, 1][9, 27, 18, 0, 1, 0, 1]Passed
disk fan[6, 10, 5, 1, 1, 1, 0][6, 10, 5, 1, 1, 1, 0]Passed
quad annulus[6, 12, 3, -3, 1, 1, 2][6, 9, 3, 0, 1, 2, 0]Failed

SHA-256 / edbe66b9a5e15832f002c4f316cddb620dd2a0cdea32b0d4bd7b4f2121597a7e

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
    edges={}
    for f in faces:
        n=len(f)
        for i in range(n):
            a,b=f[i],f[(i+1)%n]
            k=(min(a,b),max(a,b))
            edges[k]=edges.get(k,0)+1
    verts=sorted({v for f in faces for v in f})
    V=len(verts)
    E=len(edges)
    Fc=len(faces)
    chi=V-E+Fc
    parent={v:v for v in verts}
    def find(v):
        while parent[v]!=v:
            v=parent[v]
        return v
    for a,b in edges:
        ra,rb=find(a),find(b)
        if ra!=rb: parent[ra]=rb
    comps=len({find(v) for v in verts})
    bpar={}
    def bfind(v):
        while bpar[v]!=v:
            v=bpar[v]
        return v
    for (a,b),c in edges.items():
        if c==1:
            bpar.setdefault(a,a)
            bpar.setdefault(b,b)
            ra,rb=bfind(a),bfind(b)
            if ra!=rb: bpar[ra]=rb
    loops=len({bfind(v) for v in bpar})
    g=2*comps-chi-loops
    genus=None if g%2 else g//2
    return [V,E,Fc,chi,comps,loops,genus]
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]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['triangle 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]]], [9, 27, 18, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]]], [['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['disk fan', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]]], [6, 10, 5, 1, 1, 1, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['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]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]]], [['octahedron', [[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]]], [6, 12, 8, 2, 1, 0, 0]], ['quad annulus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0]]], [6, 9, 3, 0, 1, 2, 0]], ['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]]], [6, 15, 10, 1, 1, 0, None]], ['two tetrahedra', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [4, 6, 5], [4, 5, 7], [5, 6, 7], [4, 7, 6]]], [8, 12, 8, 4, 2, 0, 0]], ['gapped indices', [[[0, 1, 5], [1, 7, 5]]], [4, 5, 2, 1, 1, 1, 0]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]]], [['quad torus', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 3, 0], [3, 6, 7, 4], [4, 7, 8, 5], [5, 8, 6, 3], [6, 0, 1, 7], [7, 1, 2, 8], [8, 2, 0, 6]]], [9, 18, 9, 0, 1, 0, 1]], ['mobius strip', [[[0, 3, 4, 1], [1, 4, 5, 2], [2, 5, 0, 3]]], [6, 9, 3, 0, 1, 1, None]], ['open cylinder', [[[0, 1, 5], [0, 5, 4], [1, 2, 6], [1, 6, 5], [2, 3, 7], [2, 7, 6], [3, 0, 4], [3, 4, 7]]], [8, 16, 8, 0, 1, 2, 0]], ['book of three pages', [[[0, 1, 2], [1, 0, 3], [0, 1, 4]]], [5, 7, 3, 1, 1, 1, 0]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]]], [['tetrahedron', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]]], [4, 6, 4, 2, 1, 0, 0]], ['cube quads', [[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]]], [8, 12, 6, 2, 1, 0, 0]], ['triangle 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]]], [9, 27, 18, 0, 1, 0, 1]], ['quad grid', [[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]]], [9, 12, 4, 1, 1, 1, 0]], ['mixed quad and triangle', [[[0, 1, 2, 3], [3, 2, 4]]], [5, 6, 2, 1, 1, 1, 0]], ['tetra plus disk', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [10, 11, 12], [10, 12, 13], [10, 13, 14], [10, 14, 15], [10, 15, 11]]], [10, 16, 9, 3, 2, 1, 0]], ['tetrahedra sharing a face', [[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2], [0, 1, 4], [1, 2, 4], [0, 4, 2]]], [5, 9, 7, 3, 1, 0, None]]]]
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[4, 6, 4, 2, 1, 0, 0][4, 6, 4, 2, 1, 0, 0]Passed
cube quads[8, 12, 6, 2, 1, 0, 0][8, 12, 6, 2, 1, 0, 0]Passed
octahedron[6, 12, 8, 2, 1, 0, 0][6, 12, 8, 2, 1, 0, 0]Passed
quad torus[9, 18, 9, 0, 1, 0, 1][9, 18, 9, 0, 1, 0, 1]Passed
triangle torus[9, 27, 18, 0, 1, 0, 1][9, 27, 18, 0, 1, 0, 1]Passed
disk fan[6, 10, 5, 1, 1, 1, 0][6, 10, 5, 1, 1, 1, 0]Passed
quad annulus[6, 9, 3, 0, 1, 2, 0][6, 9, 3, 0, 1, 2, 0]Passed

SHA-256 / c821288c24e1892c86f99219472e5e4a6f49d45c3f4076536596d42e084700d1

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

Case digest / 6069e5532f8c517f2b2a5fc8be87cd8321d4233f04d7dabb25bde64e67ea05b8