FA-88671 / Mesh topology invariants / Open access
One-ring completeness is measured against the successor count · case 01
Every boundary vertex is reported non-manifold.
ROOT CAUSE
The visited ring is compared with the number of successor keys, which misses the last boundary neighbour.
VERIFIED REPAIR
Compare with the number of distinct neighbours.
Unsuccessful approach: Accepting rings that visit half the neighbours hides pinched vertices.
Case contract
Input [faces, v] with consistently oriented polygons. Each face containing v maps its next corner p to its previous corner q (counter-clockwise order around v). A repeated p is "nonmanifold"; no incident face is "isolated". If exactly one p has no predecessor the ring is a boundary fan starting there; more than one is "nonmanifold"; otherwise start at the smallest neighbour. Walk successors; a walk that does not visit every neighbour is "nonmanifold". Return [ring, "boundary"|"interior"].
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,v=x
succ={}
for f in faces:
n=len(f)
for j in range(n):
if f[j]==v:
p,q=f[(j+1)%n],f[(j-1)%n]
if p in succ: return 'nonmanifold'
succ[p]=q
if not succ: return 'isolated'
starts=[p for p in succ if p not in succ.values()]
if len(starts)>1: return 'nonmanifold'
s=starts[0] if starts else min(succ)
ring=[s]
u=s
while u in succ and succ[u]!=s:
u=succ[u]
ring.append(u)
if len(ring)!=len(succ): return 'nonmanifold'
return [ring,'boundary' if starts else 'interior']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['disk centre', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0]], [[1, 2, 3, 4, 5], 'interior']], ['disk rim vertex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 2]], [[3, 0, 1], 'boundary']], ['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['octahedron top', [[[[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, 3, 4], 'interior']], ['octahedron equator', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 2]], [[0, 1, 5, 3], 'interior']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold']], [['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['octahedron top', [[[[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, 3, 4], 'interior']], ['octahedron equator', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 2]], [[0, 1, 5, 3], 'interior']], ['bowtie pinch', [[[[0, 1, 2], [0, 3, 4]], 0]], 'nonmanifold'], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid centre', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 4]], [[1, 5, 7, 3], 'interior']], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']]], [['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid centre', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 4]], [[1, 5, 7, 3], 'interior']], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']], ['isolated vertex', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 9]], 'isolated'], ['flipped neighbour', [[[[0, 1, 2], [0, 3, 2]], 0]], 'nonmanifold'], ['same spoke twice', [[[[0, 1, 2], [0, 1, 3]], 0]], 'nonmanifold']], [['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']], ['flipped neighbour', [[[[0, 1, 2], [0, 3, 2]], 0]], 'nonmanifold'], ['same spoke twice', [[[[0, 1, 2], [0, 1, 3]], 0]], 'nonmanifold'], ['duplicated face', [[[[0, 1, 2], [0, 1, 2], [0, 2, 3]], 0]], 'nonmanifold'], ['cube corner', [[[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]], 6]], [[2, 7, 5], 'interior']], ['torus vertex', [[[[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]], 4]], [[0, 3, 7, 8, 5, 1], 'interior']]], [['disk centre', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0]], [[1, 2, 3, 4, 5], 'interior']], ['disk rim vertex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 2]], [[3, 0, 1], 'boundary']], ['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['cube corner', [[[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]], 6]], [[2, 7, 5], 'interior']], ['torus vertex', [[[[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]], 4]], [[0, 3, 7, 8, 5, 1], 'interior']]]]
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 |
|---|---|---|---|
| disk centre | [[1, 2, 3, 4, 5], 'interior'] | [[1, 2, 3, 4, 5], 'interior'] | Passed |
| disk rim vertex | nonmanifold | [[3, 0, 1], 'boundary'] | Failed |
| fan apex | nonmanifold | [[1, 2, 3, 4], 'boundary'] | Failed |
| fan middle rim | nonmanifold | [[4, 0, 2], 'boundary'] | Failed |
| octahedron top | [[1, 2, 3, 4], 'interior'] | [[1, 2, 3, 4], 'interior'] | Passed |
| octahedron equator | [[0, 1, 5, 3], 'interior'] | [[0, 1, 5, 3], 'interior'] | Passed |
| double disk pinch | nonmanifold | nonmanifold | Passed |
SHA-256 / 151a5d2de9d151e76f135d2236455b64c95ab5d1524e7dfaa129b3fb36ba846d
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,v=x
succ={}
for f in faces:
n=len(f)
for j in range(n):
if f[j]==v:
p,q=f[(j+1)%n],f[(j-1)%n]
if p in succ: return 'nonmanifold'
succ[p]=q
if not succ: return 'isolated'
starts=[p for p in succ if p not in succ.values()]
if len(starts)>1: return 'nonmanifold'
s=starts[0] if starts else min(succ)
ring=[s]
u=s
while u in succ and succ[u]!=s:
u=succ[u]
ring.append(u)
if len(ring)*2<len(set(succ)|set(succ.values())): return 'nonmanifold'
return [ring,'boundary' if starts else 'interior']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['disk centre', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0]], [[1, 2, 3, 4, 5], 'interior']], ['disk rim vertex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 2]], [[3, 0, 1], 'boundary']], ['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['octahedron top', [[[[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, 3, 4], 'interior']], ['octahedron equator', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 2]], [[0, 1, 5, 3], 'interior']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold']], [['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['octahedron top', [[[[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, 3, 4], 'interior']], ['octahedron equator', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 2]], [[0, 1, 5, 3], 'interior']], ['bowtie pinch', [[[[0, 1, 2], [0, 3, 4]], 0]], 'nonmanifold'], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid centre', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 4]], [[1, 5, 7, 3], 'interior']], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']]], [['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid centre', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 4]], [[1, 5, 7, 3], 'interior']], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']], ['isolated vertex', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 9]], 'isolated'], ['flipped neighbour', [[[[0, 1, 2], [0, 3, 2]], 0]], 'nonmanifold'], ['same spoke twice', [[[[0, 1, 2], [0, 1, 3]], 0]], 'nonmanifold']], [['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']], ['flipped neighbour', [[[[0, 1, 2], [0, 3, 2]], 0]], 'nonmanifold'], ['same spoke twice', [[[[0, 1, 2], [0, 1, 3]], 0]], 'nonmanifold'], ['duplicated face', [[[[0, 1, 2], [0, 1, 2], [0, 2, 3]], 0]], 'nonmanifold'], ['cube corner', [[[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]], 6]], [[2, 7, 5], 'interior']], ['torus vertex', [[[[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]], 4]], [[0, 3, 7, 8, 5, 1], 'interior']]], [['disk centre', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0]], [[1, 2, 3, 4, 5], 'interior']], ['disk rim vertex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 2]], [[3, 0, 1], 'boundary']], ['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['cube corner', [[[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]], 6]], [[2, 7, 5], 'interior']], ['torus vertex', [[[[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]], 4]], [[0, 3, 7, 8, 5, 1], 'interior']]]]
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 |
|---|---|---|---|
| disk centre | [[1, 2, 3, 4, 5], 'interior'] | [[1, 2, 3, 4, 5], 'interior'] | Passed |
| disk rim vertex | [[3, 0, 1], 'boundary'] | [[3, 0, 1], 'boundary'] | Passed |
| fan apex | [[1, 2, 3, 4], 'boundary'] | [[1, 2, 3, 4], 'boundary'] | Passed |
| fan middle rim | [[4, 0, 2], 'boundary'] | [[4, 0, 2], 'boundary'] | Passed |
| octahedron top | [[1, 2, 3, 4], 'interior'] | [[1, 2, 3, 4], 'interior'] | Passed |
| octahedron equator | [[0, 1, 5, 3], 'interior'] | [[0, 1, 5, 3], 'interior'] | Passed |
| double disk pinch | [[1, 2, 3, 4, 5], 'interior'] | nonmanifold | Failed |
SHA-256 / 0518c6bf7bc037ba0e3e2520360db0a50b6b1c8c306bc7d46ba0022e1cfa8640
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,v=x
succ={}
for f in faces:
n=len(f)
for j in range(n):
if f[j]==v:
p,q=f[(j+1)%n],f[(j-1)%n]
if p in succ: return 'nonmanifold'
succ[p]=q
if not succ: return 'isolated'
starts=[p for p in succ if p not in succ.values()]
if len(starts)>1: return 'nonmanifold'
s=starts[0] if starts else min(succ)
ring=[s]
u=s
while u in succ and succ[u]!=s:
u=succ[u]
ring.append(u)
if len(ring)!=len(set(succ)|set(succ.values())): return 'nonmanifold'
return [ring,'boundary' if starts else 'interior']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['disk centre', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0]], [[1, 2, 3, 4, 5], 'interior']], ['disk rim vertex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 2]], [[3, 0, 1], 'boundary']], ['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['octahedron top', [[[[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, 3, 4], 'interior']], ['octahedron equator', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 2]], [[0, 1, 5, 3], 'interior']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold']], [['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['octahedron top', [[[[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, 3, 4], 'interior']], ['octahedron equator', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 1], [5, 2, 1], [5, 3, 2], [5, 4, 3], [5, 1, 4]], 2]], [[0, 1, 5, 3], 'interior']], ['bowtie pinch', [[[[0, 1, 2], [0, 3, 4]], 0]], 'nonmanifold'], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid centre', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 4]], [[1, 5, 7, 3], 'interior']], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']]], [['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid centre', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 4]], [[1, 5, 7, 3], 'interior']], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']], ['isolated vertex', [[[[0, 2, 1], [0, 1, 3], [1, 2, 3], [0, 3, 2]], 9]], 'isolated'], ['flipped neighbour', [[[[0, 1, 2], [0, 3, 2]], 0]], 'nonmanifold'], ['same spoke twice', [[[[0, 1, 2], [0, 1, 3]], 0]], 'nonmanifold']], [['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['quad grid edge', [[[[0, 1, 4, 3], [1, 2, 5, 4], [3, 4, 7, 6], [4, 5, 8, 7]], 1]], [[2, 4, 0], 'boundary']], ['flipped neighbour', [[[[0, 1, 2], [0, 3, 2]], 0]], 'nonmanifold'], ['same spoke twice', [[[[0, 1, 2], [0, 1, 3]], 0]], 'nonmanifold'], ['duplicated face', [[[[0, 1, 2], [0, 1, 2], [0, 2, 3]], 0]], 'nonmanifold'], ['cube corner', [[[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]], 6]], [[2, 7, 5], 'interior']], ['torus vertex', [[[[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]], 4]], [[0, 3, 7, 8, 5, 1], 'interior']]], [['disk centre', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 0]], [[1, 2, 3, 4, 5], 'interior']], ['disk rim vertex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1]], 2]], [[3, 0, 1], 'boundary']], ['fan apex', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 0]], [[1, 2, 3, 4], 'boundary']], ['fan middle rim', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4]], 3]], [[4, 0, 2], 'boundary']], ['double disk pinch', [[[[0, 1, 2], [0, 2, 3], [0, 3, 4], [0, 4, 5], [0, 5, 1], [0, 6, 7], [0, 7, 8], [0, 8, 6]], 0]], 'nonmanifold'], ['cube corner', [[[[0, 3, 2, 1], [4, 5, 6, 7], [0, 1, 5, 4], [1, 2, 6, 5], [2, 3, 7, 6], [3, 0, 4, 7]], 6]], [[2, 7, 5], 'interior']], ['torus vertex', [[[[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]], 4]], [[0, 3, 7, 8, 5, 1], 'interior']]]]
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 |
|---|---|---|---|
| disk centre | [[1, 2, 3, 4, 5], 'interior'] | [[1, 2, 3, 4, 5], 'interior'] | Passed |
| disk rim vertex | [[3, 0, 1], 'boundary'] | [[3, 0, 1], 'boundary'] | Passed |
| fan apex | [[1, 2, 3, 4], 'boundary'] | [[1, 2, 3, 4], 'boundary'] | Passed |
| fan middle rim | [[4, 0, 2], 'boundary'] | [[4, 0, 2], 'boundary'] | Passed |
| octahedron top | [[1, 2, 3, 4], 'interior'] | [[1, 2, 3, 4], 'interior'] | Passed |
| octahedron equator | [[0, 1, 5, 3], 'interior'] | [[0, 1, 5, 3], 'interior'] | Passed |
| double disk pinch | nonmanifold | nonmanifold | Passed |
SHA-256 / 85d0da9801f91d1f8fa09f6bf126ec06d1573bc260cae3eece74ee508f4b9775
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.260290+00:00.
Case digest / b7e63f74397fd53559829c2a06670da58fc86fc079f2877c314a95f191c0abe0