FA-83011 / Go territory scoring / Open access
Half-point margins are truncated to whole points · case 01
W+0.5 is stored as a zero margin win.
ROOT CAUSE
The fractional digit is parsed but not added to the tenths value.
VERIFIED REPAIR
Return whole*10 + fraction digit.
Unsuccessful approach: Assuming every fractional margin is a half point turns W+3.0 into 3.5 and B+2.3 into 2.5.
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:]
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, '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']], ['W+', ['W', None, 'unknown']]], [['W+8.2', ['W', 82, 'score']], ['0', ['draw', 0, 'score']], ['Draw', ['draw', 0, 'score']], ['Jigo', ['draw', 0, 'score']], ['Void', ['void', None, 'none']], ['?', ['unknown', None, 'none']], [' B+R ', ['B', None, 'resign']], ['W+4.1', ['W', 41, 'score']]], [['B+3.5 ', ['B', 35, 'score']], [' 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']], ['B+100.5', ['B', 1005, 'score']]], [['W+0.5', ['W', 5, 'score']], ['W+3.0', ['W', 30, 'score']], ['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']], ['W+.5', ['unknown', None, 'none']]], [['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+1.1', ['B', 11, 'score']], ['B+1.1', ['B', 11, 'score']], ['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', 30, 'score'] | ['B', 35, 'score'] | Failed |
| result case 1 | ['W', 0, 'score'] | ['W', 5, 'score'] | Failed |
| result case 2 | ['W', 120, 'score'] | ['W', 120, 'score'] | Passed |
| result case 3 | ['B', 20, 'score'] | ['B', 23, 'score'] | Failed |
| result case 4 | ['W', 80, 'score'] | ['W', 82, 'score'] | Failed |
| result case 5 | ['B', 10, 'score'] | ['B', 11, 'score'] | Failed |
| result case 6 | ['B', None, 'unknown'] | ['B', None, 'unknown'] | Passed |
| result case 7 | ['W', None, 'unknown'] | ['W', None, 'unknown'] | Passed |
SHA-256 / 16f985645af57ddf4365a5d2eb1bde6d1eb0fb5aec666d6e82a0dfb104ea1fc6
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, 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 + 5 * ('.' in rest), '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']], ['W+', ['W', None, 'unknown']]], [['W+8.2', ['W', 82, 'score']], ['0', ['draw', 0, 'score']], ['Draw', ['draw', 0, 'score']], ['Jigo', ['draw', 0, 'score']], ['Void', ['void', None, 'none']], ['?', ['unknown', None, 'none']], [' B+R ', ['B', None, 'resign']], ['W+4.1', ['W', 41, 'score']]], [['B+3.5 ', ['B', 35, 'score']], [' 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']], ['B+100.5', ['B', 1005, 'score']]], [['W+0.5', ['W', 5, 'score']], ['W+3.0', ['W', 30, 'score']], ['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']], ['W+.5', ['unknown', None, 'none']]], [['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+1.1', ['B', 11, 'score']], ['B+1.1', ['B', 11, 'score']], ['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', 25, 'score'] | ['B', 23, 'score'] | Failed |
| result case 4 | ['W', 85, 'score'] | ['W', 82, 'score'] | Failed |
| result case 5 | ['B', 15, 'score'] | ['B', 11, 'score'] | Failed |
| result case 6 | ['B', None, 'unknown'] | ['B', None, 'unknown'] | Passed |
| result case 7 | ['W', None, 'unknown'] | ['W', None, 'unknown'] | Passed |
SHA-256 / b9470b57c6e0fff1a835b1294207539814d1769d8ea369ddf65f2d944408aeb8
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']], ['W+', ['W', None, 'unknown']]], [['W+8.2', ['W', 82, 'score']], ['0', ['draw', 0, 'score']], ['Draw', ['draw', 0, 'score']], ['Jigo', ['draw', 0, 'score']], ['Void', ['void', None, 'none']], ['?', ['unknown', None, 'none']], [' B+R ', ['B', None, 'resign']], ['W+4.1', ['W', 41, 'score']]], [['B+3.5 ', ['B', 35, 'score']], [' 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']], ['B+100.5', ['B', 1005, 'score']]], [['W+0.5', ['W', 5, 'score']], ['W+3.0', ['W', 30, 'score']], ['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']], ['W+.5', ['unknown', None, 'none']]], [['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+1.1', ['B', 11, 'score']], ['B+1.1', ['B', 11, 'score']], ['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 | ['W', None, 'unknown'] | ['W', None, 'unknown'] | Passed |
SHA-256 / c65b3546386e08f9b349c652e3612b8be0efccf96897a77966be5a43d1042443
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.366920+00:00.
Case digest / da9862c456d9dc0442dad3631b0125ca7b1170ac71066545bfc48bb354a5c429