FAILURE MAP
← Case archive

FA-12796 / Tournament pairing rules / Open access

Greedy pairing strands the final entrants · case 01

Greedy pairing strands the final entrants.

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

ROOT CAUSE

A locally legal first opponent is committed before checking completion.

VERIFIED REPAIR

Distinct players are sorted ids; forbidden pairs are sorted lists. Return the first complete legal pairing in ascending opponent search order, or None.

Unsuccessful approach: Choosing the last opponent instead still lacks search and violates canonical ordering.

Case contract

Synthetic model: Distinct players are sorted ids; forbidden pairs are sorted lists. Return the first complete legal pairing in ascending opponent search order, or None.

Why this case matters

Makes the stated pairing or standings policy executable without assuming any real federation rulebook.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(players, forbidden):
    remaining=list(players)
    pairs=[]
    while remaining:
        a=remaining.pop(0)
        choices=[b for b in remaining if sorted([a,b]) not in forbidden]
        if not choices: return None
        b=choices[0]; remaining.remove(b); pairs.append([a,b])
    return pairs
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('greedy dead end', solve([N,N+1,N+2,N+3], [[N+2,N+3]]), [[N,N+2],[N+1,N+3]])
check('canonical matching', solve([N,N+1,N+2,N+3], []), [[N,N+1],[N+2,N+3]])
check('empty', solve([], []), [])
check('odd count', solve([N], []), None)
check('forbidden pair', solve([N,N+1], [[N,N+1]]), None)
check('single pair', solve([N,N+1], []), [[N,N+1]])
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
greedy dead endNone[[1, 3], [2, 4]]Failed
canonical matching[[1, 2], [3, 4]][[1, 2], [3, 4]]Passed
empty[][]Passed
odd countNoneNonePassed
forbidden pairNoneNonePassed
single pair[[1, 2]][[1, 2]]Passed

SHA-256 / 1837fc65267b81fdc5d93deb586135349c6692f11d59aec3f1f9d287088666a9

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(players, forbidden):
    remaining=list(players)
    pairs=[]
    while remaining:
        a=remaining.pop(0)
        choices=[b for b in remaining if sorted([a,b]) not in forbidden]
        if not choices: return None
        b=choices[-1]; remaining.remove(b); pairs.append([a,b])
    return pairs
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('greedy dead end', solve([N,N+1,N+2,N+3], [[N+2,N+3]]), [[N,N+2],[N+1,N+3]])
check('canonical matching', solve([N,N+1,N+2,N+3], []), [[N,N+1],[N+2,N+3]])
check('empty', solve([], []), [])
check('odd count', solve([N], []), None)
check('forbidden pair', solve([N,N+1], [[N,N+1]]), None)
check('single pair', solve([N,N+1], []), [[N,N+1]])
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
greedy dead end[[1, 4], [2, 3]][[1, 3], [2, 4]]Failed
canonical matching[[1, 4], [2, 3]][[1, 2], [3, 4]]Failed
empty[][]Passed
odd countNoneNonePassed
forbidden pairNoneNonePassed
single pair[[1, 2]][[1, 2]]Passed

SHA-256 / 0ac28665af17c92d643c4f3f255f25bb494716e9a9994b25287242584ae1b710

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(players, forbidden):
    def search(rest):
        if not rest: return []
        a=rest[0]
        for b in rest[1:]:
            if sorted([a,b]) in forbidden: continue
            tail=search([x for x in rest[1:] if x!=b])
            if tail is not None: return [[a,b]]+tail
        return None
    return search(players)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('greedy dead end', solve([N,N+1,N+2,N+3], [[N+2,N+3]]), [[N,N+2],[N+1,N+3]])
check('canonical matching', solve([N,N+1,N+2,N+3], []), [[N,N+1],[N+2,N+3]])
check('empty', solve([], []), [])
check('odd count', solve([N], []), None)
check('forbidden pair', solve([N,N+1], [[N,N+1]]), None)
check('single pair', solve([N,N+1], []), [[N,N+1]])
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
greedy dead end[[1, 3], [2, 4]][[1, 3], [2, 4]]Passed
canonical matching[[1, 2], [3, 4]][[1, 2], [3, 4]]Passed
empty[][]Passed
odd countNoneNonePassed
forbidden pairNoneNonePassed
single pair[[1, 2]][[1, 2]]Passed

SHA-256 / de6f3e31aeb7c89154dc85e521560eef762225c27c0168b6013bd59032d4c59d

Verification & scope

Controlled synthetic policy; does not implement an entire tournament system. 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:39:00.127107+00:00.

Case digest / ae088fe13a1f703445814726cd32dcd8f8f45f844885ba6d7233785b2cde0f72