FA-54146 / Accessibility interaction semantics / Open access
Clearing selections unnecessarily validates stale endpoint arguments · case 01
Clearing selections unnecessarily validates stale endpoint arguments.
ROOT CAUSE
The clear validation decision in the text selection api adapter violates its declared contract.
VERIFIED REPAIR
Apply the exact contract at the clear validation decision: if kind == 'clear':
Unsuccessful approach: The local repair substitutes if kind == 'clear' and index == 0: but still mishandles the regression fixtures.
Case contract
Input [text_length,multi,readonly,selections,operation] selections ordered [anchor,focus]; operation [kind,index,anchor,focus]. API supports add,replace,remove,clear; readonly concerns text edits and does not prevent selecting. Validate endpoints inclusive0..length and index for replace/remove. add only when multi or no selection; remove preserves other ranges; clear ignores index. Return [ranges,success,active] where active is last range's focus or None. Preserve anchor direction and collapsed selections. Failure leaves input unchanged.
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,multi,readonly,selections,operation = data
ranges = [list(x) for x in selections]
kind,index,anchor,focus = operation
ok = False
if kind == 'clear' and 0 <= anchor <= length and 0 <= focus <= length: ranges,ok = [],True
elif kind in ('add','replace') and 0 <= anchor <= length and 0 <= focus <= length:
if kind == 'add' and (multi or not ranges): ranges.append([anchor,focus]); ok = True
elif kind == 'replace' and 0 <= index < len(ranges): ranges[index] = [anchor,focus]; ok = True
elif kind == 'remove' and 0 <= index < len(ranges): ranges.pop(index); ok = True
return [ranges,ok,ranges[-1][1] if ranges else None]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,True,False,[[0,1]],['add',0,N+3,N]],), [[[0,1],[N+3,N]],True,N])
check('contract fixture 2', solve([5,False,True,[],['add',0,5,5]],), [[[5,5]],True,5])
check('contract fixture 3', solve([5,False,False,[[0,1]],['add',0,2,3]],), [[[0,1]],False,1])
check('contract fixture 4', solve([5,True,False,[[0,1],[2,3]],['replace',0,4,2]],), [[[4,2],[2,3]],True,3])
check('contract fixture 5', solve([5,True,False,[[0,1],[2,3]],['remove',0,0,0]],), [[[2,3]],True,3])
check('contract fixture 6', solve([5,False,False,[[0,1]],['clear',99,-1,99]],), [[],True,None])
check('contract fixture 7', solve([5,True,False,[[0,1]],['replace',-1,2,3]],), [[[0,1]],False,1])
check('contract fixture 8', solve([5,True,False,[],['add',0,-1,3]],), [[],False,None])
check('contract fixture 9', solve([5,True,False,[],['add',0,1,6]],), [[],False,None])
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 | [[[0, 1], [4, 1]], True, 1] | [[[0, 1], [4, 1]], True, 1] | Passed |
| contract fixture 2 | [[[5, 5]], True, 5] | [[[5, 5]], True, 5] | Passed |
| contract fixture 3 | [[[0, 1]], False, 1] | [[[0, 1]], False, 1] | Passed |
| contract fixture 4 | [[[4, 2], [2, 3]], True, 3] | [[[4, 2], [2, 3]], True, 3] | Passed |
| contract fixture 5 | [[[2, 3]], True, 3] | [[[2, 3]], True, 3] | Passed |
| contract fixture 6 | [[[0, 1]], False, 1] | [[], True, None] | Failed |
| contract fixture 7 | [[[0, 1]], False, 1] | [[[0, 1]], False, 1] | Passed |
| contract fixture 8 | [[], False, None] | [[], False, None] | Passed |
| contract fixture 9 | [[], False, None] | [[], False, None] | Passed |
SHA-256 / 2b7a7fefd16a71a8f8a2c3a7d58bd85032b02b159d7dafdb2cebf1c1d690d0a3
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,multi,readonly,selections,operation = data
ranges = [list(x) for x in selections]
kind,index,anchor,focus = operation
ok = False
if kind == 'clear' and index == 0: ranges,ok = [],True
elif kind in ('add','replace') and 0 <= anchor <= length and 0 <= focus <= length:
if kind == 'add' and (multi or not ranges): ranges.append([anchor,focus]); ok = True
elif kind == 'replace' and 0 <= index < len(ranges): ranges[index] = [anchor,focus]; ok = True
elif kind == 'remove' and 0 <= index < len(ranges): ranges.pop(index); ok = True
return [ranges,ok,ranges[-1][1] if ranges else None]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,True,False,[[0,1]],['add',0,N+3,N]],), [[[0,1],[N+3,N]],True,N])
check('contract fixture 2', solve([5,False,True,[],['add',0,5,5]],), [[[5,5]],True,5])
check('contract fixture 3', solve([5,False,False,[[0,1]],['add',0,2,3]],), [[[0,1]],False,1])
check('contract fixture 4', solve([5,True,False,[[0,1],[2,3]],['replace',0,4,2]],), [[[4,2],[2,3]],True,3])
check('contract fixture 5', solve([5,True,False,[[0,1],[2,3]],['remove',0,0,0]],), [[[2,3]],True,3])
check('contract fixture 6', solve([5,False,False,[[0,1]],['clear',99,-1,99]],), [[],True,None])
check('contract fixture 7', solve([5,True,False,[[0,1]],['replace',-1,2,3]],), [[[0,1]],False,1])
check('contract fixture 8', solve([5,True,False,[],['add',0,-1,3]],), [[],False,None])
check('contract fixture 9', solve([5,True,False,[],['add',0,1,6]],), [[],False,None])
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 | [[[0, 1], [4, 1]], True, 1] | [[[0, 1], [4, 1]], True, 1] | Passed |
| contract fixture 2 | [[[5, 5]], True, 5] | [[[5, 5]], True, 5] | Passed |
| contract fixture 3 | [[[0, 1]], False, 1] | [[[0, 1]], False, 1] | Passed |
| contract fixture 4 | [[[4, 2], [2, 3]], True, 3] | [[[4, 2], [2, 3]], True, 3] | Passed |
| contract fixture 5 | [[[2, 3]], True, 3] | [[[2, 3]], True, 3] | Passed |
| contract fixture 6 | [[[0, 1]], False, 1] | [[], True, None] | Failed |
| contract fixture 7 | [[[0, 1]], False, 1] | [[[0, 1]], False, 1] | Passed |
| contract fixture 8 | [[], False, None] | [[], False, None] | Passed |
| contract fixture 9 | [[], False, None] | [[], False, None] | Passed |
SHA-256 / 03a5f067a5fc5751f30177d2d84f98c258e538d27e7fd44b9755c994d0202fbc
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,multi,readonly,selections,operation = data
ranges = [list(x) for x in selections]
kind,index,anchor,focus = operation
ok = False
if kind == 'clear': ranges,ok = [],True
elif kind in ('add','replace') and 0 <= anchor <= length and 0 <= focus <= length:
if kind == 'add' and (multi or not ranges): ranges.append([anchor,focus]); ok = True
elif kind == 'replace' and 0 <= index < len(ranges): ranges[index] = [anchor,focus]; ok = True
elif kind == 'remove' and 0 <= index < len(ranges): ranges.pop(index); ok = True
return [ranges,ok,ranges[-1][1] if ranges else None]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,True,False,[[0,1]],['add',0,N+3,N]],), [[[0,1],[N+3,N]],True,N])
check('contract fixture 2', solve([5,False,True,[],['add',0,5,5]],), [[[5,5]],True,5])
check('contract fixture 3', solve([5,False,False,[[0,1]],['add',0,2,3]],), [[[0,1]],False,1])
check('contract fixture 4', solve([5,True,False,[[0,1],[2,3]],['replace',0,4,2]],), [[[4,2],[2,3]],True,3])
check('contract fixture 5', solve([5,True,False,[[0,1],[2,3]],['remove',0,0,0]],), [[[2,3]],True,3])
check('contract fixture 6', solve([5,False,False,[[0,1]],['clear',99,-1,99]],), [[],True,None])
check('contract fixture 7', solve([5,True,False,[[0,1]],['replace',-1,2,3]],), [[[0,1]],False,1])
check('contract fixture 8', solve([5,True,False,[],['add',0,-1,3]],), [[],False,None])
check('contract fixture 9', solve([5,True,False,[],['add',0,1,6]],), [[],False,None])
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 | [[[0, 1], [4, 1]], True, 1] | [[[0, 1], [4, 1]], True, 1] | Passed |
| contract fixture 2 | [[[5, 5]], True, 5] | [[[5, 5]], True, 5] | Passed |
| contract fixture 3 | [[[0, 1]], False, 1] | [[[0, 1]], False, 1] | Passed |
| contract fixture 4 | [[[4, 2], [2, 3]], True, 3] | [[[4, 2], [2, 3]], True, 3] | Passed |
| contract fixture 5 | [[[2, 3]], True, 3] | [[[2, 3]], True, 3] | Passed |
| contract fixture 6 | [[], True, None] | [[], True, None] | Passed |
| contract fixture 7 | [[[0, 1]], False, 1] | [[[0, 1]], False, 1] | Passed |
| contract fixture 8 | [[], False, None] | [[], False, None] | Passed |
| contract fixture 9 | [[], False, None] | [[], False, None] | Passed |
SHA-256 / 725d4c725ca86d34b902a3c9b4d163c4933039170364ca138cf49147fdc9964a
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.630912+00:00.
Case digest / d276e3265bf7545dbbdaf06301a3bc902674f9d908410f79afceca7626ba3203