FA-70516 / GIS polygon topology / Open access
Simple ring validity diagnosis: closing edge adjacency · case 01
Every valid ring is reported as self-intersecting.
ROOT CAUSE
The first and last edges share the start vertex but are not excluded as adjacent, so their common vertex counts as an intersection.
VERIFIED REPAIR
At the closing edge adjacency step restore `if j == i + 1 or (i == 0 and j == n - 1):`, leaving the rest of the model unchanged.
Unsuccessful approach: Skipping every pair involving the last edge also hides genuine crossings of the closing edge.
Case contract
Input: one ring as a list of integer [x, y]. Report the first failing check in this order: fewer than 4 positions "too_few_points"; first != last "not_closed"; two cyclically consecutive equal vertices "repeated_point"; a vertex where the boundary reverses direction along a line (collinear with a negative dot product of the incoming and outgoing edge, checked cyclically) "spike"; any two non-adjacent edges sharing a point (crossing, touching or collinear overlap) "self_intersection"; otherwise "valid".
Why this case matters
Topology validators run before editing, overlay and publishing; a wrong diagnosis sends users to fix the wrong vertex or lets broken rings through.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
ring = x
if len(ring) < 4:
return 'too_few_points'
if ring[0] != ring[-1]:
return 'not_closed'
pts = ring[:-1]
n = len(pts)
for i in range(n):
if pts[i] == pts[(i + 1) % n]:
return 'repeated_point'
for i in range(n):
a, b, c = pts[i - 1], pts[i], pts[(i + 1) % n]
cross = (b[0] - a[0]) * (c[1] - b[1]) - (b[1] - a[1]) * (c[0] - b[0])
dot = (b[0] - a[0]) * (c[0] - b[0]) + (b[1] - a[1]) * (c[1] - b[1])
if cross == 0 and dot < 0:
return 'spike'
def orient(p, q, r):
v = (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0])
return (v > 0) - (v < 0)
def within(p, q, r):
return min(p[0], r[0]) <= q[0] <= max(p[0], r[0]) and min(p[1], r[1]) <= q[1] <= max(p[1], r[1])
def hit(p1, p2, p3, p4):
o1, o2, o3, o4 = orient(p1, p2, p3), orient(p1, p2, p4), orient(p3, p4, p1), orient(p3, p4, p2)
if o1 * o2 < 0 and o3 * o4 < 0:
return True
return (o1 == 0 and within(p1, p3, p2)) or (o2 == 0 and within(p1, p4, p2)) or (o3 == 0 and within(p3, p1, p4)) or (o4 == 0 and within(p3, p2, p4))
for i in range(n):
for j in range(i + 1, n):
if j == i + 1:
continue
if hit(pts[i], pts[(i + 1) % n], pts[j], pts[(j + 1) % n]):
return 'self_intersection'
return 'valid'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('control #1', [[0, 0], [10, 0], [5, 8], [0, 0]], 'valid'), ('control #2', [[0, 0], [5, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('regression #3', [[0, 0], [10, 10], [10, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #4', [[0, 0], [10, 0], [10, 10], [10, 5], [0, 5], [0, 0]], 'spike'), ('regression #5', [[5, 0], [10, 0], [10, 10], [0, 10], [0, 0], [5, 0], [0, 0]], 'not_closed'), ('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')], [('control #1', [[0, 0], [10, 0], [5, 8], [0, 0]], 'valid'), ('regression #4', [[0, 0], [10, 0], [10, 10], [10, 5], [0, 5], [0, 0]], 'spike'), ('regression #5', [[5, 0], [10, 0], [10, 10], [0, 10], [0, 0], [5, 0], [0, 0]], 'not_closed'), ('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('boundary #7', [[0, 0], [10, 0], [10, 10]], 'too_few_points'), ('boundary #8', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 1]], 'not_closed'), ('boundary #9', [[0, 0], [10, 0], [10, 0], [10, 10], [0, 0]], 'repeated_point'), ('regression #28', [[2, 0], [1, 0], [0, 3], [2, 1], [4, 1], [2, 2], [2, 0]], 'self_intersection')], [('control #2', [[0, 0], [5, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('boundary #7', [[0, 0], [10, 0], [10, 10]], 'too_few_points'), ('boundary #8', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 1]], 'not_closed'), ('boundary #9', [[0, 0], [10, 0], [10, 0], [10, 10], [0, 0]], 'repeated_point'), ('regression #10', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0], [0, 0]], 'repeated_point'), ('regression #11', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 5], [0, 12], [0, 0]], 'spike'), ('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')], [('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('regression #10', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0], [0, 0]], 'repeated_point'), ('regression #11', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 5], [0, 12], [0, 0]], 'spike'), ('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #13', [[0, 0], [4, 0], [4, 4], [8, 4], [8, 8], [4, 8], [4, 4], [0, 4], [0, 0]], 'self_intersection'), ('regression #14', [[0, 0], [10, 0], [10, 10], [5, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #15', [[0, 0], [10, 0], [10, 5], [2, 5], [6, 5], [6, 8], [0, 8], [0, 0]], 'spike'), ('regression #28', [[2, 0], [1, 0], [0, 3], [2, 1], [4, 1], [2, 2], [2, 0]], 'self_intersection')], [('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #13', [[0, 0], [4, 0], [4, 4], [8, 4], [8, 8], [4, 8], [4, 4], [0, 4], [0, 0]], 'self_intersection'), ('regression #14', [[0, 0], [10, 0], [10, 10], [5, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #15', [[0, 0], [10, 0], [10, 5], [2, 5], [6, 5], [6, 8], [0, 8], [0, 0]], 'spike'), ('control #16', [[0, 0], [6, 0], [6, 6], [3, 3], [0, 6], [0, 0]], 'valid'), ('regression #17', [[0, 0], [10, 0], [10, 10], [0, 10], [4, 10], [0, 0]], 'spike'), ('control #18', [[1, 1], [9, 2], [8, 9], [2, 7], [1, 1]], 'valid'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')]]
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 |
|---|---|---|---|
| control #0 | self_intersection | valid | Failed |
| control #1 | self_intersection | valid | Failed |
| control #2 | self_intersection | valid | Failed |
| regression #3 | self_intersection | self_intersection | Passed |
| regression #4 | spike | spike | Passed |
| regression #5 | not_closed | not_closed | Passed |
| boundary #6 | self_intersection | valid | Failed |
| regression #22 | self_intersection | self_intersection | Passed |
SHA-256 / 140f9b6626ebc45348e258c83a8ab184c764820ae5e0d8c1aa2298e65152d48d
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
ring = x
if len(ring) < 4:
return 'too_few_points'
if ring[0] != ring[-1]:
return 'not_closed'
pts = ring[:-1]
n = len(pts)
for i in range(n):
if pts[i] == pts[(i + 1) % n]:
return 'repeated_point'
for i in range(n):
a, b, c = pts[i - 1], pts[i], pts[(i + 1) % n]
cross = (b[0] - a[0]) * (c[1] - b[1]) - (b[1] - a[1]) * (c[0] - b[0])
dot = (b[0] - a[0]) * (c[0] - b[0]) + (b[1] - a[1]) * (c[1] - b[1])
if cross == 0 and dot < 0:
return 'spike'
def orient(p, q, r):
v = (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0])
return (v > 0) - (v < 0)
def within(p, q, r):
return min(p[0], r[0]) <= q[0] <= max(p[0], r[0]) and min(p[1], r[1]) <= q[1] <= max(p[1], r[1])
def hit(p1, p2, p3, p4):
o1, o2, o3, o4 = orient(p1, p2, p3), orient(p1, p2, p4), orient(p3, p4, p1), orient(p3, p4, p2)
if o1 * o2 < 0 and o3 * o4 < 0:
return True
return (o1 == 0 and within(p1, p3, p2)) or (o2 == 0 and within(p1, p4, p2)) or (o3 == 0 and within(p3, p1, p4)) or (o4 == 0 and within(p3, p2, p4))
for i in range(n):
for j in range(i + 1, n):
if j == i + 1 or j == n - 1:
continue
if hit(pts[i], pts[(i + 1) % n], pts[j], pts[(j + 1) % n]):
return 'self_intersection'
return 'valid'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('control #1', [[0, 0], [10, 0], [5, 8], [0, 0]], 'valid'), ('control #2', [[0, 0], [5, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('regression #3', [[0, 0], [10, 10], [10, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #4', [[0, 0], [10, 0], [10, 10], [10, 5], [0, 5], [0, 0]], 'spike'), ('regression #5', [[5, 0], [10, 0], [10, 10], [0, 10], [0, 0], [5, 0], [0, 0]], 'not_closed'), ('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')], [('control #1', [[0, 0], [10, 0], [5, 8], [0, 0]], 'valid'), ('regression #4', [[0, 0], [10, 0], [10, 10], [10, 5], [0, 5], [0, 0]], 'spike'), ('regression #5', [[5, 0], [10, 0], [10, 10], [0, 10], [0, 0], [5, 0], [0, 0]], 'not_closed'), ('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('boundary #7', [[0, 0], [10, 0], [10, 10]], 'too_few_points'), ('boundary #8', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 1]], 'not_closed'), ('boundary #9', [[0, 0], [10, 0], [10, 0], [10, 10], [0, 0]], 'repeated_point'), ('regression #28', [[2, 0], [1, 0], [0, 3], [2, 1], [4, 1], [2, 2], [2, 0]], 'self_intersection')], [('control #2', [[0, 0], [5, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('boundary #7', [[0, 0], [10, 0], [10, 10]], 'too_few_points'), ('boundary #8', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 1]], 'not_closed'), ('boundary #9', [[0, 0], [10, 0], [10, 0], [10, 10], [0, 0]], 'repeated_point'), ('regression #10', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0], [0, 0]], 'repeated_point'), ('regression #11', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 5], [0, 12], [0, 0]], 'spike'), ('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')], [('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('regression #10', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0], [0, 0]], 'repeated_point'), ('regression #11', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 5], [0, 12], [0, 0]], 'spike'), ('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #13', [[0, 0], [4, 0], [4, 4], [8, 4], [8, 8], [4, 8], [4, 4], [0, 4], [0, 0]], 'self_intersection'), ('regression #14', [[0, 0], [10, 0], [10, 10], [5, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #15', [[0, 0], [10, 0], [10, 5], [2, 5], [6, 5], [6, 8], [0, 8], [0, 0]], 'spike'), ('regression #28', [[2, 0], [1, 0], [0, 3], [2, 1], [4, 1], [2, 2], [2, 0]], 'self_intersection')], [('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #13', [[0, 0], [4, 0], [4, 4], [8, 4], [8, 8], [4, 8], [4, 4], [0, 4], [0, 0]], 'self_intersection'), ('regression #14', [[0, 0], [10, 0], [10, 10], [5, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #15', [[0, 0], [10, 0], [10, 5], [2, 5], [6, 5], [6, 8], [0, 8], [0, 0]], 'spike'), ('control #16', [[0, 0], [6, 0], [6, 6], [3, 3], [0, 6], [0, 0]], 'valid'), ('regression #17', [[0, 0], [10, 0], [10, 10], [0, 10], [4, 10], [0, 0]], 'spike'), ('control #18', [[1, 1], [9, 2], [8, 9], [2, 7], [1, 1]], 'valid'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')]]
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 |
|---|---|---|---|
| control #0 | valid | valid | Passed |
| control #1 | valid | valid | Passed |
| control #2 | valid | valid | Passed |
| regression #3 | self_intersection | self_intersection | Passed |
| regression #4 | spike | spike | Passed |
| regression #5 | not_closed | not_closed | Passed |
| boundary #6 | valid | valid | Passed |
| regression #22 | valid | self_intersection | Failed |
SHA-256 / 241e54dd227a64f2db6e539bb8f1ef1dbe3fa64fec3a678e9900b1140bad94a8
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
ring = x
if len(ring) < 4:
return 'too_few_points'
if ring[0] != ring[-1]:
return 'not_closed'
pts = ring[:-1]
n = len(pts)
for i in range(n):
if pts[i] == pts[(i + 1) % n]:
return 'repeated_point'
for i in range(n):
a, b, c = pts[i - 1], pts[i], pts[(i + 1) % n]
cross = (b[0] - a[0]) * (c[1] - b[1]) - (b[1] - a[1]) * (c[0] - b[0])
dot = (b[0] - a[0]) * (c[0] - b[0]) + (b[1] - a[1]) * (c[1] - b[1])
if cross == 0 and dot < 0:
return 'spike'
def orient(p, q, r):
v = (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0])
return (v > 0) - (v < 0)
def within(p, q, r):
return min(p[0], r[0]) <= q[0] <= max(p[0], r[0]) and min(p[1], r[1]) <= q[1] <= max(p[1], r[1])
def hit(p1, p2, p3, p4):
o1, o2, o3, o4 = orient(p1, p2, p3), orient(p1, p2, p4), orient(p3, p4, p1), orient(p3, p4, p2)
if o1 * o2 < 0 and o3 * o4 < 0:
return True
return (o1 == 0 and within(p1, p3, p2)) or (o2 == 0 and within(p1, p4, p2)) or (o3 == 0 and within(p3, p1, p4)) or (o4 == 0 and within(p3, p2, p4))
for i in range(n):
for j in range(i + 1, n):
if j == i + 1 or (i == 0 and j == n - 1):
continue
if hit(pts[i], pts[(i + 1) % n], pts[j], pts[(j + 1) % n]):
return 'self_intersection'
return 'valid'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control #0', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('control #1', [[0, 0], [10, 0], [5, 8], [0, 0]], 'valid'), ('control #2', [[0, 0], [5, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('regression #3', [[0, 0], [10, 10], [10, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #4', [[0, 0], [10, 0], [10, 10], [10, 5], [0, 5], [0, 0]], 'spike'), ('regression #5', [[5, 0], [10, 0], [10, 10], [0, 10], [0, 0], [5, 0], [0, 0]], 'not_closed'), ('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')], [('control #1', [[0, 0], [10, 0], [5, 8], [0, 0]], 'valid'), ('regression #4', [[0, 0], [10, 0], [10, 10], [10, 5], [0, 5], [0, 0]], 'spike'), ('regression #5', [[5, 0], [10, 0], [10, 10], [0, 10], [0, 0], [5, 0], [0, 0]], 'not_closed'), ('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('boundary #7', [[0, 0], [10, 0], [10, 10]], 'too_few_points'), ('boundary #8', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 1]], 'not_closed'), ('boundary #9', [[0, 0], [10, 0], [10, 0], [10, 10], [0, 0]], 'repeated_point'), ('regression #28', [[2, 0], [1, 0], [0, 3], [2, 1], [4, 1], [2, 2], [2, 0]], 'self_intersection')], [('control #2', [[0, 0], [5, 0], [10, 0], [10, 10], [0, 10], [0, 0]], 'valid'), ('boundary #7', [[0, 0], [10, 0], [10, 10]], 'too_few_points'), ('boundary #8', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 1]], 'not_closed'), ('boundary #9', [[0, 0], [10, 0], [10, 0], [10, 10], [0, 0]], 'repeated_point'), ('regression #10', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0], [0, 0]], 'repeated_point'), ('regression #11', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 5], [0, 12], [0, 0]], 'spike'), ('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')], [('boundary #6', [[0, 0], [10, 0], [10, 10], [0, 0]], 'valid'), ('regression #10', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 0], [0, 0]], 'repeated_point'), ('regression #11', [[0, 0], [10, 0], [10, 10], [0, 10], [0, 5], [0, 12], [0, 0]], 'spike'), ('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #13', [[0, 0], [4, 0], [4, 4], [8, 4], [8, 8], [4, 8], [4, 4], [0, 4], [0, 0]], 'self_intersection'), ('regression #14', [[0, 0], [10, 0], [10, 10], [5, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #15', [[0, 0], [10, 0], [10, 5], [2, 5], [6, 5], [6, 8], [0, 8], [0, 0]], 'spike'), ('regression #28', [[2, 0], [1, 0], [0, 3], [2, 1], [4, 1], [2, 2], [2, 0]], 'self_intersection')], [('regression #12', [[0, 5], [0, 0], [10, 0], [10, 10], [0, 10], [0, 12], [0, 5]], 'spike'), ('regression #13', [[0, 0], [4, 0], [4, 4], [8, 4], [8, 8], [4, 8], [4, 4], [0, 4], [0, 0]], 'self_intersection'), ('regression #14', [[0, 0], [10, 0], [10, 10], [5, 0], [0, 10], [0, 0]], 'self_intersection'), ('regression #15', [[0, 0], [10, 0], [10, 5], [2, 5], [6, 5], [6, 8], [0, 8], [0, 0]], 'spike'), ('control #16', [[0, 0], [6, 0], [6, 6], [3, 3], [0, 6], [0, 0]], 'valid'), ('regression #17', [[0, 0], [10, 0], [10, 10], [0, 10], [4, 10], [0, 0]], 'spike'), ('control #18', [[1, 1], [9, 2], [8, 9], [2, 7], [1, 1]], 'valid'), ('regression #22', [[0, 0], [10, 0], [0, 10], [10, 10], [0, 0]], 'self_intersection')]]
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 |
|---|---|---|---|
| control #0 | valid | valid | Passed |
| control #1 | valid | valid | Passed |
| control #2 | valid | valid | Passed |
| regression #3 | self_intersection | self_intersection | Passed |
| regression #4 | spike | spike | Passed |
| regression #5 | not_closed | not_closed | Passed |
| boundary #6 | valid | valid | Passed |
| regression #22 | self_intersection | self_intersection | Passed |
SHA-256 / 03738e615dd353bda5bc50063aa6b2026cfadbb3bf793af4af31a34e3862ae61
Verification & scope
Stipulated deterministic toy contract on a bounded input domain; results are rounded as stated and no conformance with any published standard or library is claimed. 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:48:21.438956+00:00.
Case digest / a3a9e8a8a2463819b4be91bf31d90b1e1381b6dd45968e268a5a66809bba3129