FAILURE MAP
← Case archive

FA-53451 / Accessibility interaction semantics / Open access

Range start rounds into the next text character · case 01

Range start rounds into the next text character.

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

ROOT CAUSE

The start surrogate decision in the text range bridge adapter violates its declared contract.

VERIFIED REPAIR

Apply the exact contract at the start surrogate decision: max(i for i,x in enumerate(edges) if x <= start)

Unsuccessful approach: The local repair substitutes max(i for i,x in enumerate(edges) if x <= start) if start == 0 else min(i for i,x in enumerate(edges) if x >= start) but still mishandles the regression fixtures.

Case contract

Input [text,start,end,unit] where indices are measured in utf16 or codepoint units. Negative indices count backward from end, clamp to valid extent, and sort reversed endpoints. A boundary inside a surrogate pair expands outward (start down, end up). CRLF is exposed as one LF after slicing. NUL becomes replacement character. Return [exposed_text,normalized_start,normalized_end,source_units]. UTF16 offsets refer to original source, not normalized text.

Why this case matters

Offline accessibility bridge model with explicit policy; useful for testing semantic API adapters independently of browser implementations.

1 / The failure

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

N = 1
observations = []
def solve(data):
    text,start,end,unit = data
    widths = [2 if unit == 'utf16' and ord(c) > 65535 else 1 for c in text]
    edges = [0]
    for width in widths: edges.append(edges[-1]+width)
    size = edges[-1]
    if start < 0: start += size
    if end < 0: end += size
    start = min(size,max(0,start))
    end = min(size,max(0,end))
    if start > end: start,end = end,start
    left = min(i for i,x in enumerate(edges) if x >= start)
    right = min(i for i,x in enumerate(edges) if x >= end)
    snippet = text[left:right].replace('\r\n','\n').replace('\x00','\ufffd')
    return [snippet,edges[left],edges[right],size]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('surrogate interior expands', solve(['A'*N+'😀Z',N+1,N+2,'utf16'],), ['😀',N,N+2,N+3])
check('negative start', solve(['A'*N+'BC',-2,N+2,'codepoint'],), ['BC',N,N+2,N+2])
check('negative end', solve(['A'*N+'BC',N,-1,'codepoint'],), ['B',N,N+1,N+2])
check('clamp both', solve(['AB',-20,40,'utf16'],), ['AB',0,2,2])
check('reverse', solve(['ABCDE',4,1,'codepoint'],), ['BCD',1,4,5])
check('CRLF normalization', solve(['A\r\nB',0,4,'utf16'],), ['A\nB',0,4,4])
check('NUL replacement', solve(['A\x00B',0,3,'utf16'],), ['A�B',0,3,3])
check('codepoint emoji', solve(['😀B',1,2,'codepoint'],), ['B',1,2,2])
check('empty', solve(['',0,0,'utf16'],), ['',0,0,0])
check('surrogate end expands', solve(['A😀Z',0,2,'utf16'],), ['A😀',0,3,4])
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
surrogate interior expands['', 3, 3, 4]['😀', 1, 3, 4]Failed
negative start['BC', 1, 3, 3]['BC', 1, 3, 3]Passed
negative end['B', 1, 2, 3]['B', 1, 2, 3]Passed
clamp both['AB', 0, 2, 2]['AB', 0, 2, 2]Passed
reverse['BCD', 1, 4, 5]['BCD', 1, 4, 5]Passed
CRLF normalization['A\nB', 0, 4, 4]['A\nB', 0, 4, 4]Passed
NUL replacement['A�B', 0, 3, 3]['A�B', 0, 3, 3]Passed
codepoint emoji['B', 1, 2, 2]['B', 1, 2, 2]Passed
empty['', 0, 0, 0]['', 0, 0, 0]Passed
surrogate end expands['A😀', 0, 3, 4]['A😀', 0, 3, 4]Passed

SHA-256 / ec1c455f5fddf0727b23345c9423ac092a2c59b05b755512aedea3ac6a24ff0b

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(data):
    text,start,end,unit = data
    widths = [2 if unit == 'utf16' and ord(c) > 65535 else 1 for c in text]
    edges = [0]
    for width in widths: edges.append(edges[-1]+width)
    size = edges[-1]
    if start < 0: start += size
    if end < 0: end += size
    start = min(size,max(0,start))
    end = min(size,max(0,end))
    if start > end: start,end = end,start
    left = max(i for i,x in enumerate(edges) if x <= start) if start == 0 else min(i for i,x in enumerate(edges) if x >= start)
    right = min(i for i,x in enumerate(edges) if x >= end)
    snippet = text[left:right].replace('\r\n','\n').replace('\x00','\ufffd')
    return [snippet,edges[left],edges[right],size]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('surrogate interior expands', solve(['A'*N+'😀Z',N+1,N+2,'utf16'],), ['😀',N,N+2,N+3])
check('negative start', solve(['A'*N+'BC',-2,N+2,'codepoint'],), ['BC',N,N+2,N+2])
check('negative end', solve(['A'*N+'BC',N,-1,'codepoint'],), ['B',N,N+1,N+2])
check('clamp both', solve(['AB',-20,40,'utf16'],), ['AB',0,2,2])
check('reverse', solve(['ABCDE',4,1,'codepoint'],), ['BCD',1,4,5])
check('CRLF normalization', solve(['A\r\nB',0,4,'utf16'],), ['A\nB',0,4,4])
check('NUL replacement', solve(['A\x00B',0,3,'utf16'],), ['A�B',0,3,3])
check('codepoint emoji', solve(['😀B',1,2,'codepoint'],), ['B',1,2,2])
check('empty', solve(['',0,0,'utf16'],), ['',0,0,0])
check('surrogate end expands', solve(['A😀Z',0,2,'utf16'],), ['A😀',0,3,4])
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
surrogate interior expands['', 3, 3, 4]['😀', 1, 3, 4]Failed
negative start['BC', 1, 3, 3]['BC', 1, 3, 3]Passed
negative end['B', 1, 2, 3]['B', 1, 2, 3]Passed
clamp both['AB', 0, 2, 2]['AB', 0, 2, 2]Passed
reverse['BCD', 1, 4, 5]['BCD', 1, 4, 5]Passed
CRLF normalization['A\nB', 0, 4, 4]['A\nB', 0, 4, 4]Passed
NUL replacement['A�B', 0, 3, 3]['A�B', 0, 3, 3]Passed
codepoint emoji['B', 1, 2, 2]['B', 1, 2, 2]Passed
empty['', 0, 0, 0]['', 0, 0, 0]Passed
surrogate end expands['A😀', 0, 3, 4]['A😀', 0, 3, 4]Passed

SHA-256 / c4a76f8e538c4afcceba8251f5975be472b57406ffc97733b62a4ed741990837

3 / The verified repair

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

N = 1
observations = []
def solve(data):
    text,start,end,unit = data
    widths = [2 if unit == 'utf16' and ord(c) > 65535 else 1 for c in text]
    edges = [0]
    for width in widths: edges.append(edges[-1]+width)
    size = edges[-1]
    if start < 0: start += size
    if end < 0: end += size
    start = min(size,max(0,start))
    end = min(size,max(0,end))
    if start > end: start,end = end,start
    left = max(i for i,x in enumerate(edges) if x <= start)
    right = min(i for i,x in enumerate(edges) if x >= end)
    snippet = text[left:right].replace('\r\n','\n').replace('\x00','\ufffd')
    return [snippet,edges[left],edges[right],size]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('surrogate interior expands', solve(['A'*N+'😀Z',N+1,N+2,'utf16'],), ['😀',N,N+2,N+3])
check('negative start', solve(['A'*N+'BC',-2,N+2,'codepoint'],), ['BC',N,N+2,N+2])
check('negative end', solve(['A'*N+'BC',N,-1,'codepoint'],), ['B',N,N+1,N+2])
check('clamp both', solve(['AB',-20,40,'utf16'],), ['AB',0,2,2])
check('reverse', solve(['ABCDE',4,1,'codepoint'],), ['BCD',1,4,5])
check('CRLF normalization', solve(['A\r\nB',0,4,'utf16'],), ['A\nB',0,4,4])
check('NUL replacement', solve(['A\x00B',0,3,'utf16'],), ['A�B',0,3,3])
check('codepoint emoji', solve(['😀B',1,2,'codepoint'],), ['B',1,2,2])
check('empty', solve(['',0,0,'utf16'],), ['',0,0,0])
check('surrogate end expands', solve(['A😀Z',0,2,'utf16'],), ['A😀',0,3,4])
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
surrogate interior expands['😀', 1, 3, 4]['😀', 1, 3, 4]Passed
negative start['BC', 1, 3, 3]['BC', 1, 3, 3]Passed
negative end['B', 1, 2, 3]['B', 1, 2, 3]Passed
clamp both['AB', 0, 2, 2]['AB', 0, 2, 2]Passed
reverse['BCD', 1, 4, 5]['BCD', 1, 4, 5]Passed
CRLF normalization['A\nB', 0, 4, 4]['A\nB', 0, 4, 4]Passed
NUL replacement['A�B', 0, 3, 3]['A�B', 0, 3, 3]Passed
codepoint emoji['B', 1, 2, 2]['B', 1, 2, 2]Passed
empty['', 0, 0, 0]['', 0, 0, 0]Passed
surrogate end expands['A😀', 0, 3, 4]['A😀', 0, 3, 4]Passed

SHA-256 / 7eaa050111be90c437ec742e294457f17a16a44e622078e38a0dd32f96a504e1

Verification & scope

Stipulated finite adapter contract, not a claim of platform accessibility or ARIA conformance. 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:45:39.170279+00:00.

Case digest / 4973471743c1a19d8e5e790035f5d61e4d5be8be80543ddf7764cbd7fa0d7686