FA-83321 / Go territory scoring / Open access
Surplus handicap stones are accepted · case 01
Black places more free handicap stones than agreed.
ROOT CAUSE
The count test only rejects too few stones.
VERIFIED REPAIR
Require exactly count stones.
Unsuccessful approach: Rejecting only surplus stones accepts incomplete placements.
Case contract
Input [size, count, stones]. Check in order: every stone on the board ("range"), no duplicate ("duplicate"), exactly count stones and 2 <= count <= 9 ("count"). Otherwise "ok".
Why this case matters
Go servers and scoring tools compute this value automatically; a wrong answer changes a game result.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
size, count, stones = x
seen = set()
for r, c in stones:
if not (0 <= r < size and 0 <= c < size):
return 'range'
for r, c in stones:
if (r, c) in seen:
return 'duplicate'
seen.add((r, c))
if len(stones) < count:
return 'count'
if count < 2 or count > 9:
return 'count'
return 'ok'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[19, 9, [[3, 17], [1, 1], [7, 14], [1, 11], [0, 9], [7, 13], [15, 1], [12, 18], [13, 0], [2, 13]]], 'count'], [[19, 6, [[11, 2], [8, 5], [4, 4], [13, 0], [13, 0], [18, 7], [16, 11]]], 'duplicate'], [[13, 10, [[2, 5], [11, 3], [10, 11], [11, 4], [8, 9], [8, 12], [12, 10], [10, 2], [5, 4], [9, 5], [2, 5]]], 'duplicate'], [[9, 7, [[6, 0], [6, 0], [8, 5], [0, 0], [6, 3], [0, 5], [1, 3]]], 'duplicate'], [[9, 5, [[-1, 7], [0, 2], [8, 4], [4, 1]]], 'range'], [[13, 6, [[3, 6], [11, 11], [4, 13], [9, 0], [1, 1], [12, 9], [3, 6]]], 'range'], [[9, 3, [[8, 1], [5, 2], [6, 2], [7, 2], [8, 1]]], 'duplicate'], [[19, 8, [[9, 4], [12, 2], [8, 12], [9, 15], [3, 17], [4, 10], [14, 17]]], 'count']], [[[19, 4, [[7, 1], [8, 9], [14, 2], [11, 12], [7, 1]]], 'duplicate'], [[19, 1, [[16, 11]]], 'count'], [[9, 4, [[6, 3], [1, 8], [0, 0], [6, 3]]], 'duplicate'], [[13, 6, [[0, 10], [10, 12], [0, 10], [12, 10], [9, 2], [6, 8]]], 'duplicate'], [[19, 8, [[12, 5], [16, 15], [17, 16], [10, 3], [0, 13], [14, 9], [7, 1], [9, 11]]], 'ok'], [[9, 6, [[3, 5], [1, 3], [5, 6], [2, 2], [0, 4], [8, 1], [1, 7]]], 'count'], [[13, 6, [[11, 11], [5, 6], [8, 12], [8, 0], [10, 6], [1, 9], [2, 8]]], 'count'], [[13, 5, [[11, 11], [12, 8], [3, 3], [7, 0]]], 'count']], [[[13, 6, [[11, 11], [5, 6], [8, 12], [8, 0], [10, 6], [1, 9], [2, 8]]], 'count'], [[13, 4, [[6, 3], [6, 5], [6, 11]]], 'count'], [[9, 10, [[5, 7], [1, 6], [6, 6], [4, 3], [4, 6], [5, 8], [7, 5], [5, 0], [5, 3], [5, 7]]], 'duplicate'], [[9, 5, [[3, 6], [8, 4], [0, 2], [7, 8], [1, 7]]], 'ok'], [[9, 1, [[1, 5], [7, 2]]], 'count'], [[13, 3, [[10, 0], [0, 11]]], 'count'], [[9, 2, [[3, 0], [2, 4], [6, 5]]], 'count'], [[9, 3, [[1, 1], [2, 2]]], 'count']], [[[13, 3, [[5, 9], [5, 9], [2, 6]]], 'duplicate'], [[13, 2, [[1, 3], [12, 8]]], 'ok'], [[19, 4, [[4, 4], [6, 18], [15, 18], [12, 5]]], 'ok'], [[13, 0, []], 'count'], [[19, 5, [[7, 1], [7, 3], [13, 10], [3, 11], [3, 8]]], 'ok'], [[19, 7, [[8, 18], [18, 18], [12, 4], [10, 13], [16, 1], [8, 1], [14, 7], [8, 18]]], 'duplicate'], [[9, 4, [[7, 3], [8, 3], [3, 0]]], 'count'], [[19, 7, [[7, 15], [15, 17], [17, 14], [13, 0], [5, 8], [7, 1], [14, 6], [11, 12]]], 'count']], [[[13, 10, [[11, 9], [11, 11], [7, 2], [0, 2], [10, 3], [11, 5], [7, 6], [1, 10], [3, 2], [3, 12]]], 'count'], [[13, 4, [[6, 0], [7, 9], [12, 11], [11, 9], [12, 5]]], 'count'], [[19, 1, [[10, 17], [11, 15]]], 'count'], [[13, 8, [[12, 0], [8, 0], [9, 8], [8, 5], [2, 3], [5, 12], [7, 5], [5, 0]]], 'ok'], [[13, 4, [[3, 7], [1, 12], [0, 11], [4, 6]]], 'ok'], [[13, 2, [[0, 10], [1, 4], [0, 10]]], 'duplicate'], [[19, 6, [[0, 8], [2, 10], [17, 12], [2, 15], [5, 4]]], 'count'], [[19, 5, [[7, 12], [7, 1], [13, 10], [1, 9], [14, 1], [0, 4]]], 'count']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("free placement case %d" % i, 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 |
|---|---|---|---|
| free placement case 0 | ok | count | Failed |
| free placement case 1 | duplicate | duplicate | Passed |
| free placement case 2 | duplicate | duplicate | Passed |
| free placement case 3 | duplicate | duplicate | Passed |
| free placement case 4 | range | range | Passed |
| free placement case 5 | range | range | Passed |
| free placement case 6 | duplicate | duplicate | Passed |
| free placement case 7 | count | count | Passed |
SHA-256 / 1720fb9200f02e7f46084dcb5f491960ee351e78f3bf7b17e428cbb916a1be80
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
size, count, stones = x
seen = set()
for r, c in stones:
if not (0 <= r < size and 0 <= c < size):
return 'range'
for r, c in stones:
if (r, c) in seen:
return 'duplicate'
seen.add((r, c))
if len(stones) > count:
return 'count'
if count < 2 or count > 9:
return 'count'
return 'ok'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[19, 9, [[3, 17], [1, 1], [7, 14], [1, 11], [0, 9], [7, 13], [15, 1], [12, 18], [13, 0], [2, 13]]], 'count'], [[19, 6, [[11, 2], [8, 5], [4, 4], [13, 0], [13, 0], [18, 7], [16, 11]]], 'duplicate'], [[13, 10, [[2, 5], [11, 3], [10, 11], [11, 4], [8, 9], [8, 12], [12, 10], [10, 2], [5, 4], [9, 5], [2, 5]]], 'duplicate'], [[9, 7, [[6, 0], [6, 0], [8, 5], [0, 0], [6, 3], [0, 5], [1, 3]]], 'duplicate'], [[9, 5, [[-1, 7], [0, 2], [8, 4], [4, 1]]], 'range'], [[13, 6, [[3, 6], [11, 11], [4, 13], [9, 0], [1, 1], [12, 9], [3, 6]]], 'range'], [[9, 3, [[8, 1], [5, 2], [6, 2], [7, 2], [8, 1]]], 'duplicate'], [[19, 8, [[9, 4], [12, 2], [8, 12], [9, 15], [3, 17], [4, 10], [14, 17]]], 'count']], [[[19, 4, [[7, 1], [8, 9], [14, 2], [11, 12], [7, 1]]], 'duplicate'], [[19, 1, [[16, 11]]], 'count'], [[9, 4, [[6, 3], [1, 8], [0, 0], [6, 3]]], 'duplicate'], [[13, 6, [[0, 10], [10, 12], [0, 10], [12, 10], [9, 2], [6, 8]]], 'duplicate'], [[19, 8, [[12, 5], [16, 15], [17, 16], [10, 3], [0, 13], [14, 9], [7, 1], [9, 11]]], 'ok'], [[9, 6, [[3, 5], [1, 3], [5, 6], [2, 2], [0, 4], [8, 1], [1, 7]]], 'count'], [[13, 6, [[11, 11], [5, 6], [8, 12], [8, 0], [10, 6], [1, 9], [2, 8]]], 'count'], [[13, 5, [[11, 11], [12, 8], [3, 3], [7, 0]]], 'count']], [[[13, 6, [[11, 11], [5, 6], [8, 12], [8, 0], [10, 6], [1, 9], [2, 8]]], 'count'], [[13, 4, [[6, 3], [6, 5], [6, 11]]], 'count'], [[9, 10, [[5, 7], [1, 6], [6, 6], [4, 3], [4, 6], [5, 8], [7, 5], [5, 0], [5, 3], [5, 7]]], 'duplicate'], [[9, 5, [[3, 6], [8, 4], [0, 2], [7, 8], [1, 7]]], 'ok'], [[9, 1, [[1, 5], [7, 2]]], 'count'], [[13, 3, [[10, 0], [0, 11]]], 'count'], [[9, 2, [[3, 0], [2, 4], [6, 5]]], 'count'], [[9, 3, [[1, 1], [2, 2]]], 'count']], [[[13, 3, [[5, 9], [5, 9], [2, 6]]], 'duplicate'], [[13, 2, [[1, 3], [12, 8]]], 'ok'], [[19, 4, [[4, 4], [6, 18], [15, 18], [12, 5]]], 'ok'], [[13, 0, []], 'count'], [[19, 5, [[7, 1], [7, 3], [13, 10], [3, 11], [3, 8]]], 'ok'], [[19, 7, [[8, 18], [18, 18], [12, 4], [10, 13], [16, 1], [8, 1], [14, 7], [8, 18]]], 'duplicate'], [[9, 4, [[7, 3], [8, 3], [3, 0]]], 'count'], [[19, 7, [[7, 15], [15, 17], [17, 14], [13, 0], [5, 8], [7, 1], [14, 6], [11, 12]]], 'count']], [[[13, 10, [[11, 9], [11, 11], [7, 2], [0, 2], [10, 3], [11, 5], [7, 6], [1, 10], [3, 2], [3, 12]]], 'count'], [[13, 4, [[6, 0], [7, 9], [12, 11], [11, 9], [12, 5]]], 'count'], [[19, 1, [[10, 17], [11, 15]]], 'count'], [[13, 8, [[12, 0], [8, 0], [9, 8], [8, 5], [2, 3], [5, 12], [7, 5], [5, 0]]], 'ok'], [[13, 4, [[3, 7], [1, 12], [0, 11], [4, 6]]], 'ok'], [[13, 2, [[0, 10], [1, 4], [0, 10]]], 'duplicate'], [[19, 6, [[0, 8], [2, 10], [17, 12], [2, 15], [5, 4]]], 'count'], [[19, 5, [[7, 12], [7, 1], [13, 10], [1, 9], [14, 1], [0, 4]]], 'count']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("free placement case %d" % i, 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 |
|---|---|---|---|
| free placement case 0 | count | count | Passed |
| free placement case 1 | duplicate | duplicate | Passed |
| free placement case 2 | duplicate | duplicate | Passed |
| free placement case 3 | duplicate | duplicate | Passed |
| free placement case 4 | range | range | Passed |
| free placement case 5 | range | range | Passed |
| free placement case 6 | duplicate | duplicate | Passed |
| free placement case 7 | ok | count | Failed |
SHA-256 / 0f9f539a036416e554a9a33c7d0b7f1aedbd36bf99db191d101155e93976488f
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
size, count, stones = x
seen = set()
for r, c in stones:
if not (0 <= r < size and 0 <= c < size):
return 'range'
for r, c in stones:
if (r, c) in seen:
return 'duplicate'
seen.add((r, c))
if len(stones) != count:
return 'count'
if count < 2 or count > 9:
return 'count'
return 'ok'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[19, 9, [[3, 17], [1, 1], [7, 14], [1, 11], [0, 9], [7, 13], [15, 1], [12, 18], [13, 0], [2, 13]]], 'count'], [[19, 6, [[11, 2], [8, 5], [4, 4], [13, 0], [13, 0], [18, 7], [16, 11]]], 'duplicate'], [[13, 10, [[2, 5], [11, 3], [10, 11], [11, 4], [8, 9], [8, 12], [12, 10], [10, 2], [5, 4], [9, 5], [2, 5]]], 'duplicate'], [[9, 7, [[6, 0], [6, 0], [8, 5], [0, 0], [6, 3], [0, 5], [1, 3]]], 'duplicate'], [[9, 5, [[-1, 7], [0, 2], [8, 4], [4, 1]]], 'range'], [[13, 6, [[3, 6], [11, 11], [4, 13], [9, 0], [1, 1], [12, 9], [3, 6]]], 'range'], [[9, 3, [[8, 1], [5, 2], [6, 2], [7, 2], [8, 1]]], 'duplicate'], [[19, 8, [[9, 4], [12, 2], [8, 12], [9, 15], [3, 17], [4, 10], [14, 17]]], 'count']], [[[19, 4, [[7, 1], [8, 9], [14, 2], [11, 12], [7, 1]]], 'duplicate'], [[19, 1, [[16, 11]]], 'count'], [[9, 4, [[6, 3], [1, 8], [0, 0], [6, 3]]], 'duplicate'], [[13, 6, [[0, 10], [10, 12], [0, 10], [12, 10], [9, 2], [6, 8]]], 'duplicate'], [[19, 8, [[12, 5], [16, 15], [17, 16], [10, 3], [0, 13], [14, 9], [7, 1], [9, 11]]], 'ok'], [[9, 6, [[3, 5], [1, 3], [5, 6], [2, 2], [0, 4], [8, 1], [1, 7]]], 'count'], [[13, 6, [[11, 11], [5, 6], [8, 12], [8, 0], [10, 6], [1, 9], [2, 8]]], 'count'], [[13, 5, [[11, 11], [12, 8], [3, 3], [7, 0]]], 'count']], [[[13, 6, [[11, 11], [5, 6], [8, 12], [8, 0], [10, 6], [1, 9], [2, 8]]], 'count'], [[13, 4, [[6, 3], [6, 5], [6, 11]]], 'count'], [[9, 10, [[5, 7], [1, 6], [6, 6], [4, 3], [4, 6], [5, 8], [7, 5], [5, 0], [5, 3], [5, 7]]], 'duplicate'], [[9, 5, [[3, 6], [8, 4], [0, 2], [7, 8], [1, 7]]], 'ok'], [[9, 1, [[1, 5], [7, 2]]], 'count'], [[13, 3, [[10, 0], [0, 11]]], 'count'], [[9, 2, [[3, 0], [2, 4], [6, 5]]], 'count'], [[9, 3, [[1, 1], [2, 2]]], 'count']], [[[13, 3, [[5, 9], [5, 9], [2, 6]]], 'duplicate'], [[13, 2, [[1, 3], [12, 8]]], 'ok'], [[19, 4, [[4, 4], [6, 18], [15, 18], [12, 5]]], 'ok'], [[13, 0, []], 'count'], [[19, 5, [[7, 1], [7, 3], [13, 10], [3, 11], [3, 8]]], 'ok'], [[19, 7, [[8, 18], [18, 18], [12, 4], [10, 13], [16, 1], [8, 1], [14, 7], [8, 18]]], 'duplicate'], [[9, 4, [[7, 3], [8, 3], [3, 0]]], 'count'], [[19, 7, [[7, 15], [15, 17], [17, 14], [13, 0], [5, 8], [7, 1], [14, 6], [11, 12]]], 'count']], [[[13, 10, [[11, 9], [11, 11], [7, 2], [0, 2], [10, 3], [11, 5], [7, 6], [1, 10], [3, 2], [3, 12]]], 'count'], [[13, 4, [[6, 0], [7, 9], [12, 11], [11, 9], [12, 5]]], 'count'], [[19, 1, [[10, 17], [11, 15]]], 'count'], [[13, 8, [[12, 0], [8, 0], [9, 8], [8, 5], [2, 3], [5, 12], [7, 5], [5, 0]]], 'ok'], [[13, 4, [[3, 7], [1, 12], [0, 11], [4, 6]]], 'ok'], [[13, 2, [[0, 10], [1, 4], [0, 10]]], 'duplicate'], [[19, 6, [[0, 8], [2, 10], [17, 12], [2, 15], [5, 4]]], 'count'], [[19, 5, [[7, 12], [7, 1], [13, 10], [1, 9], [14, 1], [0, 4]]], 'count']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("free placement case %d" % i, 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 |
|---|---|---|---|
| free placement case 0 | count | count | Passed |
| free placement case 1 | duplicate | duplicate | Passed |
| free placement case 2 | duplicate | duplicate | Passed |
| free placement case 3 | duplicate | duplicate | Passed |
| free placement case 4 | range | range | Passed |
| free placement case 5 | range | range | Passed |
| free placement case 6 | duplicate | duplicate | Passed |
| free placement case 7 | count | count | Passed |
SHA-256 / 18d0d5033cd2f636e028177461b9a8a929f7c891fabbbc6dbecde043d3bf8414
Verification & scope
Small rectangular toy boards given as strings of B, W and dot; a bounded teaching model of one scoring or bookkeeping rule, not a complete rules engine or server implementation. 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:50:20.622820+00:00.
Case digest / 8c67fd6ffaa8db709fffad0fd636352f0a40338774d71df3f35123e185e13c35