FA-53761 / Accessibility interaction semantics / Open access
Attribute run includes its exclusive end character · case 01
Attribute run includes its exclusive end character.
ROOT CAUSE
The run end decision in the text attribute runs adapter violates its declared contract.
VERIFIED REPAIR
Apply the exact contract at the run end decision: pos < min(length,e)
Unsuccessful approach: The local repair substitutes pos < min(length,e)-1 but still mishandles the regression fixtures.
Case contract
Input [length,default_attributes,spans] where spans are [start,end,attributes,priority]. Clamp endpoints to [0,length], discard empty/reversed spans. At each character position merge active spans over defaults by increasing priority, preserving input tie order; None attribute removes that attribute. Build maximal equal adjacent runs [start,end,attributes]. Zero length returns empty. Offsets are codepoints. Dictionary values are strings or None.
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,defaults,spans = data
points = []
for pos in range(length):
attrs = dict(defaults)
active = [(p,i,a) for i,(s,e,a,p) in enumerate(spans) if max(0,s) <= pos <= min(length,e)]
for priority,idx,updates in sorted(active,key=lambda x:(x[0],x[1])):
for key,value in updates.items():
if value is None: attrs.pop(key,None)
else: attrs[key] = value
points.append(attrs)
result = []
for pos,attrs in enumerate(points):
if result and result[-1][2] == attrs: result[-1][1] = pos+1
else: result.append([pos,pos+1,attrs])
return result
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+2,{'lang':'en'},[[0,N,{'weight':'bold'},1],[1,N+1,{'lang':'fr'},2]]],), [[0,1,{'lang':'en','weight':'bold'}]]+([[1,N,{'lang':'fr','weight':'bold'}]] if N>1 else [])+[[N,N+1,{'lang':'fr'}],[N+1,N+2,{'lang':'en'}]])
check('contract fixture 2', solve([3,{'lang':'en','color':'red'},[[0,3,{'lang':None},1],[1,2,{'color':'blue'},2]]],), [[0,1,{'color':'red'}],[1,2,{'color':'blue'}],[2,3,{'color':'red'}]])
check('contract fixture 3', solve([3,{},[[0,3,{'x':'high'},5],[0,3,{'x':'low'},1]]],), [[0,3,{'x':'high'}]])
check('contract fixture 4', solve([3,{},[[0,3,{'x':'first'},1],[0,3,{'x':'last'},1]]],), [[0,3,{'x':'last'}]])
check('contract fixture 5', solve([3,{},[[-3,2,{'x':'a'},0],[2,8,{'x':'a'},0],[2,1,{'x':'bad'},9]]],), [[0,3,{'x':'a'}]])
check('contract fixture 6', solve([0,{'lang':'en'},[]],), [])
check('contract fixture 7', solve([2,{'lang':'en'},[[0,1,{},0]]],), [[0,2,{'lang':'en'}]])
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, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr', 'weight': 'bold'}], [2, 3, {'lang': 'fr'}]] | [[0, 1, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr'}], [2, 3, {'lang': 'en'}]] | Failed |
| contract fixture 2 | [[0, 1, {'color': 'red'}], [1, 3, {'color': 'blue'}]] | [[0, 1, {'color': 'red'}], [1, 2, {'color': 'blue'}], [2, 3, {'color': 'red'}]] | Failed |
| contract fixture 3 | [[0, 3, {'x': 'high'}]] | [[0, 3, {'x': 'high'}]] | Passed |
| contract fixture 4 | [[0, 3, {'x': 'last'}]] | [[0, 3, {'x': 'last'}]] | Passed |
| contract fixture 5 | [[0, 3, {'x': 'a'}]] | [[0, 3, {'x': 'a'}]] | Passed |
| contract fixture 6 | [] | [] | Passed |
| contract fixture 7 | [[0, 2, {'lang': 'en'}]] | [[0, 2, {'lang': 'en'}]] | Passed |
SHA-256 / c8e486051f249216129b3e9f7df19f18a70aa1fde1a7bfa5d6fb4dea5621cfe5
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,defaults,spans = data
points = []
for pos in range(length):
attrs = dict(defaults)
active = [(p,i,a) for i,(s,e,a,p) in enumerate(spans) if max(0,s) <= pos < min(length,e)-1]
for priority,idx,updates in sorted(active,key=lambda x:(x[0],x[1])):
for key,value in updates.items():
if value is None: attrs.pop(key,None)
else: attrs[key] = value
points.append(attrs)
result = []
for pos,attrs in enumerate(points):
if result and result[-1][2] == attrs: result[-1][1] = pos+1
else: result.append([pos,pos+1,attrs])
return result
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+2,{'lang':'en'},[[0,N,{'weight':'bold'},1],[1,N+1,{'lang':'fr'},2]]],), [[0,1,{'lang':'en','weight':'bold'}]]+([[1,N,{'lang':'fr','weight':'bold'}]] if N>1 else [])+[[N,N+1,{'lang':'fr'}],[N+1,N+2,{'lang':'en'}]])
check('contract fixture 2', solve([3,{'lang':'en','color':'red'},[[0,3,{'lang':None},1],[1,2,{'color':'blue'},2]]],), [[0,1,{'color':'red'}],[1,2,{'color':'blue'}],[2,3,{'color':'red'}]])
check('contract fixture 3', solve([3,{},[[0,3,{'x':'high'},5],[0,3,{'x':'low'},1]]],), [[0,3,{'x':'high'}]])
check('contract fixture 4', solve([3,{},[[0,3,{'x':'first'},1],[0,3,{'x':'last'},1]]],), [[0,3,{'x':'last'}]])
check('contract fixture 5', solve([3,{},[[-3,2,{'x':'a'},0],[2,8,{'x':'a'},0],[2,1,{'x':'bad'},9]]],), [[0,3,{'x':'a'}]])
check('contract fixture 6', solve([0,{'lang':'en'},[]],), [])
check('contract fixture 7', solve([2,{'lang':'en'},[[0,1,{},0]]],), [[0,2,{'lang':'en'}]])
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, 3, {'lang': 'en'}]] | [[0, 1, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr'}], [2, 3, {'lang': 'en'}]] | Failed |
| contract fixture 2 | [[0, 2, {'color': 'red'}], [2, 3, {'color': 'red', 'lang': 'en'}]] | [[0, 1, {'color': 'red'}], [1, 2, {'color': 'blue'}], [2, 3, {'color': 'red'}]] | Failed |
| contract fixture 3 | [[0, 2, {'x': 'high'}], [2, 3, {}]] | [[0, 3, {'x': 'high'}]] | Failed |
| contract fixture 4 | [[0, 2, {'x': 'last'}], [2, 3, {}]] | [[0, 3, {'x': 'last'}]] | Failed |
| contract fixture 5 | [[0, 1, {'x': 'a'}], [1, 3, {}]] | [[0, 3, {'x': 'a'}]] | Failed |
| contract fixture 6 | [] | [] | Passed |
| contract fixture 7 | [[0, 2, {'lang': 'en'}]] | [[0, 2, {'lang': 'en'}]] | Passed |
SHA-256 / c9a477b8b5b8390311629664e1922763a5f979a76378a67b4ee60a9fdd4facbd
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,defaults,spans = data
points = []
for pos in range(length):
attrs = dict(defaults)
active = [(p,i,a) for i,(s,e,a,p) in enumerate(spans) if max(0,s) <= pos < min(length,e)]
for priority,idx,updates in sorted(active,key=lambda x:(x[0],x[1])):
for key,value in updates.items():
if value is None: attrs.pop(key,None)
else: attrs[key] = value
points.append(attrs)
result = []
for pos,attrs in enumerate(points):
if result and result[-1][2] == attrs: result[-1][1] = pos+1
else: result.append([pos,pos+1,attrs])
return result
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+2,{'lang':'en'},[[0,N,{'weight':'bold'},1],[1,N+1,{'lang':'fr'},2]]],), [[0,1,{'lang':'en','weight':'bold'}]]+([[1,N,{'lang':'fr','weight':'bold'}]] if N>1 else [])+[[N,N+1,{'lang':'fr'}],[N+1,N+2,{'lang':'en'}]])
check('contract fixture 2', solve([3,{'lang':'en','color':'red'},[[0,3,{'lang':None},1],[1,2,{'color':'blue'},2]]],), [[0,1,{'color':'red'}],[1,2,{'color':'blue'}],[2,3,{'color':'red'}]])
check('contract fixture 3', solve([3,{},[[0,3,{'x':'high'},5],[0,3,{'x':'low'},1]]],), [[0,3,{'x':'high'}]])
check('contract fixture 4', solve([3,{},[[0,3,{'x':'first'},1],[0,3,{'x':'last'},1]]],), [[0,3,{'x':'last'}]])
check('contract fixture 5', solve([3,{},[[-3,2,{'x':'a'},0],[2,8,{'x':'a'},0],[2,1,{'x':'bad'},9]]],), [[0,3,{'x':'a'}]])
check('contract fixture 6', solve([0,{'lang':'en'},[]],), [])
check('contract fixture 7', solve([2,{'lang':'en'},[[0,1,{},0]]],), [[0,2,{'lang':'en'}]])
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, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr'}], [2, 3, {'lang': 'en'}]] | [[0, 1, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr'}], [2, 3, {'lang': 'en'}]] | Passed |
| contract fixture 2 | [[0, 1, {'color': 'red'}], [1, 2, {'color': 'blue'}], [2, 3, {'color': 'red'}]] | [[0, 1, {'color': 'red'}], [1, 2, {'color': 'blue'}], [2, 3, {'color': 'red'}]] | Passed |
| contract fixture 3 | [[0, 3, {'x': 'high'}]] | [[0, 3, {'x': 'high'}]] | Passed |
| contract fixture 4 | [[0, 3, {'x': 'last'}]] | [[0, 3, {'x': 'last'}]] | Passed |
| contract fixture 5 | [[0, 3, {'x': 'a'}]] | [[0, 3, {'x': 'a'}]] | Passed |
| contract fixture 6 | [] | [] | Passed |
| contract fixture 7 | [[0, 2, {'lang': 'en'}]] | [[0, 2, {'lang': 'en'}]] | Passed |
SHA-256 / 32ebd0cffac1988cd1602c91ab559cbf8a7e675b59a345a2c31984585f7ebbf5
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:41.953280+00:00.
Case digest / e167e5b850df09e348620af6792a53bd17632a21c1e291a800531c275eae0640