FA-83031 / Go territory scoring / Open access
A winner with no margin is parsed as unknown · case 01
RE[B+] loses the winner.
ROOT CAUSE
The empty-margin branch is missing so the empty margin fails digit parsing.
VERIFIED REPAIR
Return [winner, None, "unknown"] for an empty margin.
Unsuccessful approach: Returning a zero score margin invents a numeric result.
Case contract
Input an SGF RE string. "0", "Draw", "Jigo" -> ["draw", 0, "score"]; "Void" -> ["void", None, "none"]; C+R/Resign, C+T/Time, C+F/Forfeit (case-insensitive) -> [C, None, reason]; "C+" -> [C, None, "unknown"]; C+digits with optional one-digit fraction -> [C, tenths, "score"]; else unknown.
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):
s = x.strip()
if s in ('0', 'Draw', 'Jigo'):
return ['draw', 0, 'score']
if s == 'Void':
return ['void', None, 'none']
if len(s) < 2 or s[0] not in 'BW' or s[1] != '+':
return ['unknown', None, 'none']
who = s[0]
rest = s[2:]
word = rest.lower()
for key, reason in (('r', 'resign'), ('t', 'time'), ('f', 'forfeit')):
if word in (key, reason):
return [who, None, reason]
if '.' in rest:
whole, _, frac = rest.partition('.')
else:
whole, frac = rest, '0'
if not whole.isdigit() or not frac.isdigit() or len(frac) != 1:
return ['unknown', None, 'none']
return [who, int(whole) * 10 + int(frac), 'score']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['B+3.5', ['B', 35, 'score']], ['W+0.5', ['W', 5, 'score']], ['W+12', ['W', 120, 'score']], ['B+2.3', ['B', 23, 'score']], ['W+8.2', ['W', 82, 'score']], ['B+1.1', ['B', 11, 'score']], ['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']]], [['W+', ['W', None, 'unknown']], ['W+', ['W', None, 'unknown']], ['0', ['draw', 0, 'score']], ['Draw', ['draw', 0, 'score']], ['Jigo', ['draw', 0, 'score']], ['Void', ['void', None, 'none']], ['?', ['unknown', None, 'none']], [' B+R ', ['B', None, 'resign']]], [['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']], [' W+7', ['W', 70, 'score']], ['X+3', ['unknown', None, 'none']], ['B-3', ['unknown', None, 'none']], ['B+3.25', ['unknown', None, 'none']], ['W+3.0', ['W', 30, 'score']], ['B+6.0', ['B', 60, 'score']]], [['W+', ['W', None, 'unknown']], ['W+', ['W', None, 'unknown']], ['B+Rough', ['unknown', None, 'none']], ['W+Timeout', ['unknown', None, 'none']], ['B+r', ['B', None, 'resign']], ['W+t', ['W', None, 'time']], ['B+100.5', ['B', 1005, 'score']], ['W+4.1', ['W', 41, 'score']]], [['B+R', ['B', None, 'resign']], ['W+Resign', ['W', None, 'resign']], ['B+resign', ['B', None, 'resign']], ['W+T', ['W', None, 'time']], ['B+Time', ['B', None, 'time']], ['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']], ['B+7.', ['unknown', None, 'none']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("result 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 |
|---|---|---|---|
| result case 0 | ['B', 35, 'score'] | ['B', 35, 'score'] | Passed |
| result case 1 | ['W', 5, 'score'] | ['W', 5, 'score'] | Passed |
| result case 2 | ['W', 120, 'score'] | ['W', 120, 'score'] | Passed |
| result case 3 | ['B', 23, 'score'] | ['B', 23, 'score'] | Passed |
| result case 4 | ['W', 82, 'score'] | ['W', 82, 'score'] | Passed |
| result case 5 | ['B', 11, 'score'] | ['B', 11, 'score'] | Passed |
| result case 6 | ['unknown', None, 'none'] | ['B', None, 'unknown'] | Failed |
| result case 7 | ['unknown', None, 'none'] | ['B', None, 'unknown'] | Failed |
SHA-256 / b3f85b67935154e0bfe50dce38bec678f2011005cb22a31d71c0849502669f40
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
s = x.strip()
if s in ('0', 'Draw', 'Jigo'):
return ['draw', 0, 'score']
if s == 'Void':
return ['void', None, 'none']
if len(s) < 2 or s[0] not in 'BW' or s[1] != '+':
return ['unknown', None, 'none']
who = s[0]
rest = s[2:]
if rest == '':
return [who, 0, 'score']
word = rest.lower()
for key, reason in (('r', 'resign'), ('t', 'time'), ('f', 'forfeit')):
if word in (key, reason):
return [who, None, reason]
if '.' in rest:
whole, _, frac = rest.partition('.')
else:
whole, frac = rest, '0'
if not whole.isdigit() or not frac.isdigit() or len(frac) != 1:
return ['unknown', None, 'none']
return [who, int(whole) * 10 + int(frac), 'score']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['B+3.5', ['B', 35, 'score']], ['W+0.5', ['W', 5, 'score']], ['W+12', ['W', 120, 'score']], ['B+2.3', ['B', 23, 'score']], ['W+8.2', ['W', 82, 'score']], ['B+1.1', ['B', 11, 'score']], ['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']]], [['W+', ['W', None, 'unknown']], ['W+', ['W', None, 'unknown']], ['0', ['draw', 0, 'score']], ['Draw', ['draw', 0, 'score']], ['Jigo', ['draw', 0, 'score']], ['Void', ['void', None, 'none']], ['?', ['unknown', None, 'none']], [' B+R ', ['B', None, 'resign']]], [['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']], [' W+7', ['W', 70, 'score']], ['X+3', ['unknown', None, 'none']], ['B-3', ['unknown', None, 'none']], ['B+3.25', ['unknown', None, 'none']], ['W+3.0', ['W', 30, 'score']], ['B+6.0', ['B', 60, 'score']]], [['W+', ['W', None, 'unknown']], ['W+', ['W', None, 'unknown']], ['B+Rough', ['unknown', None, 'none']], ['W+Timeout', ['unknown', None, 'none']], ['B+r', ['B', None, 'resign']], ['W+t', ['W', None, 'time']], ['B+100.5', ['B', 1005, 'score']], ['W+4.1', ['W', 41, 'score']]], [['B+R', ['B', None, 'resign']], ['W+Resign', ['W', None, 'resign']], ['B+resign', ['B', None, 'resign']], ['W+T', ['W', None, 'time']], ['B+Time', ['B', None, 'time']], ['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']], ['B+7.', ['unknown', None, 'none']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("result 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 |
|---|---|---|---|
| result case 0 | ['B', 35, 'score'] | ['B', 35, 'score'] | Passed |
| result case 1 | ['W', 5, 'score'] | ['W', 5, 'score'] | Passed |
| result case 2 | ['W', 120, 'score'] | ['W', 120, 'score'] | Passed |
| result case 3 | ['B', 23, 'score'] | ['B', 23, 'score'] | Passed |
| result case 4 | ['W', 82, 'score'] | ['W', 82, 'score'] | Passed |
| result case 5 | ['B', 11, 'score'] | ['B', 11, 'score'] | Passed |
| result case 6 | ['B', 0, 'score'] | ['B', None, 'unknown'] | Failed |
| result case 7 | ['B', 0, 'score'] | ['B', None, 'unknown'] | Failed |
SHA-256 / ee61d25a8a0b6052d15f091040d9ebc9435d740512660325b56fd6d33296f12c
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
s = x.strip()
if s in ('0', 'Draw', 'Jigo'):
return ['draw', 0, 'score']
if s == 'Void':
return ['void', None, 'none']
if len(s) < 2 or s[0] not in 'BW' or s[1] != '+':
return ['unknown', None, 'none']
who = s[0]
rest = s[2:]
if rest == '':
return [who, None, 'unknown']
word = rest.lower()
for key, reason in (('r', 'resign'), ('t', 'time'), ('f', 'forfeit')):
if word in (key, reason):
return [who, None, reason]
if '.' in rest:
whole, _, frac = rest.partition('.')
else:
whole, frac = rest, '0'
if not whole.isdigit() or not frac.isdigit() or len(frac) != 1:
return ['unknown', None, 'none']
return [who, int(whole) * 10 + int(frac), 'score']
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['B+3.5', ['B', 35, 'score']], ['W+0.5', ['W', 5, 'score']], ['W+12', ['W', 120, 'score']], ['B+2.3', ['B', 23, 'score']], ['W+8.2', ['W', 82, 'score']], ['B+1.1', ['B', 11, 'score']], ['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']]], [['W+', ['W', None, 'unknown']], ['W+', ['W', None, 'unknown']], ['0', ['draw', 0, 'score']], ['Draw', ['draw', 0, 'score']], ['Jigo', ['draw', 0, 'score']], ['Void', ['void', None, 'none']], ['?', ['unknown', None, 'none']], [' B+R ', ['B', None, 'resign']]], [['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']], [' W+7', ['W', 70, 'score']], ['X+3', ['unknown', None, 'none']], ['B-3', ['unknown', None, 'none']], ['B+3.25', ['unknown', None, 'none']], ['W+3.0', ['W', 30, 'score']], ['B+6.0', ['B', 60, 'score']]], [['W+', ['W', None, 'unknown']], ['W+', ['W', None, 'unknown']], ['B+Rough', ['unknown', None, 'none']], ['W+Timeout', ['unknown', None, 'none']], ['B+r', ['B', None, 'resign']], ['W+t', ['W', None, 'time']], ['B+100.5', ['B', 1005, 'score']], ['W+4.1', ['W', 41, 'score']]], [['B+R', ['B', None, 'resign']], ['W+Resign', ['W', None, 'resign']], ['B+resign', ['B', None, 'resign']], ['W+T', ['W', None, 'time']], ['B+Time', ['B', None, 'time']], ['B+', ['B', None, 'unknown']], ['B+', ['B', None, 'unknown']], ['B+7.', ['unknown', None, 'none']]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("result 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 |
|---|---|---|---|
| result case 0 | ['B', 35, 'score'] | ['B', 35, 'score'] | Passed |
| result case 1 | ['W', 5, 'score'] | ['W', 5, 'score'] | Passed |
| result case 2 | ['W', 120, 'score'] | ['W', 120, 'score'] | Passed |
| result case 3 | ['B', 23, 'score'] | ['B', 23, 'score'] | Passed |
| result case 4 | ['W', 82, 'score'] | ['W', 82, 'score'] | Passed |
| result case 5 | ['B', 11, 'score'] | ['B', 11, 'score'] | Passed |
| result case 6 | ['B', None, 'unknown'] | ['B', None, 'unknown'] | Passed |
| result case 7 | ['B', None, 'unknown'] | ['B', None, 'unknown'] | Passed |
SHA-256 / 384da03d3a5a715ccad8410bc5ffcb8f98a2cfd1d6ec6c8aa0bfb958625c30bf
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:17.835470+00:00.
Case digest / 7b0d4457cb6771869b380a40970d37975af4afd44dc1229b628c92b0a714a5b8