FA-54181 / Accessibility interaction semantics / Open access
Zero-width annotations are exposed as text spans · case 01
Zero-width annotations are exposed as text spans.
ROOT CAUSE
The annotation empty decision in the annotation ranges adapter violates its declared contract.
VERIFIED REPAIR
Apply the exact contract at the annotation empty decision: start >= end
Unsuccessful approach: The local repair substitutes start > end or start == end == 0 and False but still mishandles the regression fixtures.
Case contract
Input [length,annotations,types] annotations [id,start,end,kind,detail,resolved]. Admit allowed types and unresolved annotations with nonempty detail. Clamp half-open ranges, discard empty or reversed. Preserve overlapping annotations; dedupe same ID by first eligible record. Output sorted by start,end,ID. Return [id,start,end,kind,detail]. Spelling, grammar, comment are the only recognized kinds even if types requests unknown types.
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):
length,annotations,types = data
seen = set()
result = []
for ident,start,end,kind,detail,resolved in annotations:
if kind not in {'spelling','grammar','comment'} or kind not in types: continue
if resolved or not detail: continue
start,end = max(0,start),min(length,end)
if start > end or ident in seen: continue
seen.add(ident)
result.append([ident,start,end,kind,detail])
return sorted(result,key=lambda row:(row[1],row[2],row[0]))
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,[['b',N,N+3,'comment','B',False],['a',N,N+2,'spelling','A',False],['c',N,N+2,'grammar','C',False]],['comment','spelling','grammar']],), [['a',N,N+2,'spelling','A'],['c',N,N+2,'grammar','C'],['b',N,N+3,'comment','B']])
check('contract fixture 2', solve([4,[['a',-2,2,'comment','A',False],['b',2,8,'comment','B',False]],['comment']],), [['a',0,2,'comment','A'],['b',2,4,'comment','B']])
check('contract fixture 3', solve([4,[['a',0,2,'comment','A',True],['b',0,2,'spelling','B',False],['c',0,2,'unknown','C',False],['d',0,2,'comment','',False]],['comment','unknown']],), [])
check('contract fixture 4', solve([4,[['a',0,0,'comment','zero',False],['b',3,1,'comment','reverse',False]],['comment']],), [])
check('contract fixture 5', solve([4,[['a',2,3,'comment','first',False],['a',0,1,'comment','later',False]],['comment']],), [['a',2,3,'comment','first']])
check('contract fixture 6', solve([4,[['a',0,2,'comment','resolved',True],['a',1,3,'comment','live',False]],['comment']],), [['a',1,3,'comment','live']])
check('contract fixture 7', solve([0,[],[]],), [])
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 |
|---|---|---|---|
| contract fixture 1 | [['a', 1, 3, 'spelling', 'A'], ['c', 1, 3, 'grammar', 'C'], ['b', 1, 4, 'comment', 'B']] | [['a', 1, 3, 'spelling', 'A'], ['c', 1, 3, 'grammar', 'C'], ['b', 1, 4, 'comment', 'B']] | Passed |
| contract fixture 2 | [['a', 0, 2, 'comment', 'A'], ['b', 2, 4, 'comment', 'B']] | [['a', 0, 2, 'comment', 'A'], ['b', 2, 4, 'comment', 'B']] | Passed |
| contract fixture 3 | [] | [] | Passed |
| contract fixture 4 | [['a', 0, 0, 'comment', 'zero']] | [] | Failed |
| contract fixture 5 | [['a', 2, 3, 'comment', 'first']] | [['a', 2, 3, 'comment', 'first']] | Passed |
| contract fixture 6 | [['a', 1, 3, 'comment', 'live']] | [['a', 1, 3, 'comment', 'live']] | Passed |
| contract fixture 7 | [] | [] | Passed |
SHA-256 / 70f1d0daaabf84480171469fc161fcee240d014036e9ef68b70497e893d8a4c0
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,annotations,types = data
seen = set()
result = []
for ident,start,end,kind,detail,resolved in annotations:
if kind not in {'spelling','grammar','comment'} or kind not in types: continue
if resolved or not detail: continue
start,end = max(0,start),min(length,end)
if start > end or start == end == 0 and False or ident in seen: continue
seen.add(ident)
result.append([ident,start,end,kind,detail])
return sorted(result,key=lambda row:(row[1],row[2],row[0]))
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,[['b',N,N+3,'comment','B',False],['a',N,N+2,'spelling','A',False],['c',N,N+2,'grammar','C',False]],['comment','spelling','grammar']],), [['a',N,N+2,'spelling','A'],['c',N,N+2,'grammar','C'],['b',N,N+3,'comment','B']])
check('contract fixture 2', solve([4,[['a',-2,2,'comment','A',False],['b',2,8,'comment','B',False]],['comment']],), [['a',0,2,'comment','A'],['b',2,4,'comment','B']])
check('contract fixture 3', solve([4,[['a',0,2,'comment','A',True],['b',0,2,'spelling','B',False],['c',0,2,'unknown','C',False],['d',0,2,'comment','',False]],['comment','unknown']],), [])
check('contract fixture 4', solve([4,[['a',0,0,'comment','zero',False],['b',3,1,'comment','reverse',False]],['comment']],), [])
check('contract fixture 5', solve([4,[['a',2,3,'comment','first',False],['a',0,1,'comment','later',False]],['comment']],), [['a',2,3,'comment','first']])
check('contract fixture 6', solve([4,[['a',0,2,'comment','resolved',True],['a',1,3,'comment','live',False]],['comment']],), [['a',1,3,'comment','live']])
check('contract fixture 7', solve([0,[],[]],), [])
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 |
|---|---|---|---|
| contract fixture 1 | [['a', 1, 3, 'spelling', 'A'], ['c', 1, 3, 'grammar', 'C'], ['b', 1, 4, 'comment', 'B']] | [['a', 1, 3, 'spelling', 'A'], ['c', 1, 3, 'grammar', 'C'], ['b', 1, 4, 'comment', 'B']] | Passed |
| contract fixture 2 | [['a', 0, 2, 'comment', 'A'], ['b', 2, 4, 'comment', 'B']] | [['a', 0, 2, 'comment', 'A'], ['b', 2, 4, 'comment', 'B']] | Passed |
| contract fixture 3 | [] | [] | Passed |
| contract fixture 4 | [['a', 0, 0, 'comment', 'zero']] | [] | Failed |
| contract fixture 5 | [['a', 2, 3, 'comment', 'first']] | [['a', 2, 3, 'comment', 'first']] | Passed |
| contract fixture 6 | [['a', 1, 3, 'comment', 'live']] | [['a', 1, 3, 'comment', 'live']] | Passed |
| contract fixture 7 | [] | [] | Passed |
SHA-256 / 53b9ca3972a6b977cf2ffd3d04033574975e06012ce40da330784642a0f069a5
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,annotations,types = data
seen = set()
result = []
for ident,start,end,kind,detail,resolved in annotations:
if kind not in {'spelling','grammar','comment'} or kind not in types: continue
if resolved or not detail: continue
start,end = max(0,start),min(length,end)
if start >= end or ident in seen: continue
seen.add(ident)
result.append([ident,start,end,kind,detail])
return sorted(result,key=lambda row:(row[1],row[2],row[0]))
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,[['b',N,N+3,'comment','B',False],['a',N,N+2,'spelling','A',False],['c',N,N+2,'grammar','C',False]],['comment','spelling','grammar']],), [['a',N,N+2,'spelling','A'],['c',N,N+2,'grammar','C'],['b',N,N+3,'comment','B']])
check('contract fixture 2', solve([4,[['a',-2,2,'comment','A',False],['b',2,8,'comment','B',False]],['comment']],), [['a',0,2,'comment','A'],['b',2,4,'comment','B']])
check('contract fixture 3', solve([4,[['a',0,2,'comment','A',True],['b',0,2,'spelling','B',False],['c',0,2,'unknown','C',False],['d',0,2,'comment','',False]],['comment','unknown']],), [])
check('contract fixture 4', solve([4,[['a',0,0,'comment','zero',False],['b',3,1,'comment','reverse',False]],['comment']],), [])
check('contract fixture 5', solve([4,[['a',2,3,'comment','first',False],['a',0,1,'comment','later',False]],['comment']],), [['a',2,3,'comment','first']])
check('contract fixture 6', solve([4,[['a',0,2,'comment','resolved',True],['a',1,3,'comment','live',False]],['comment']],), [['a',1,3,'comment','live']])
check('contract fixture 7', solve([0,[],[]],), [])
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 |
|---|---|---|---|
| contract fixture 1 | [['a', 1, 3, 'spelling', 'A'], ['c', 1, 3, 'grammar', 'C'], ['b', 1, 4, 'comment', 'B']] | [['a', 1, 3, 'spelling', 'A'], ['c', 1, 3, 'grammar', 'C'], ['b', 1, 4, 'comment', 'B']] | Passed |
| contract fixture 2 | [['a', 0, 2, 'comment', 'A'], ['b', 2, 4, 'comment', 'B']] | [['a', 0, 2, 'comment', 'A'], ['b', 2, 4, 'comment', 'B']] | Passed |
| contract fixture 3 | [] | [] | Passed |
| contract fixture 4 | [] | [] | Passed |
| contract fixture 5 | [['a', 2, 3, 'comment', 'first']] | [['a', 2, 3, 'comment', 'first']] | Passed |
| contract fixture 6 | [['a', 1, 3, 'comment', 'live']] | [['a', 1, 3, 'comment', 'live']] | Passed |
| contract fixture 7 | [] | [] | Passed |
SHA-256 / 39109e157ea14e2f5b0807fb3b8e6c50af9a6caf8a6cb9f64f2daa8f2be3f1f0
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:45.906669+00:00.
Case digest / ee1e1a3715770b02c8e8b1c4dac4fc4cf09a4e34ea201ea2c5b30682a8a7d0a4