FAILURE MAP
← Case archive

FA-83031 / Go territory scoring / Open access

A winner with no margin is parsed as unknown · case 01

RE[B+] loses the winner.

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

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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