FA-53786 / Accessibility interaction semantics / Open access
Text run updates omit preexisting attribute replacements · case 01
Text run updates omit preexisting attribute replacements.
ROOT CAUSE
The span updates decision in the text attribute runs adapter violates its declared contract.
VERIFIED REPAIR
Apply the exact contract at the span updates decision: else: attrs[key] = value
Unsuccessful approach: The local repair substitutes else: attrs[key] = value if key not in defaults else defaults[key] 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.setdefault(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, 3, {'lang': 'en'}]] | [[0, 1, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr'}], [2, 3, {'lang': 'en'}]] | Failed |
| contract fixture 2 | [[0, 3, {'color': 'red'}]] | [[0, 1, {'color': 'red'}], [1, 2, {'color': 'blue'}], [2, 3, {'color': 'red'}]] | Failed |
| contract fixture 3 | [[0, 3, {'x': 'low'}]] | [[0, 3, {'x': 'high'}]] | Failed |
| contract fixture 4 | [[0, 3, {'x': 'first'}]] | [[0, 3, {'x': 'last'}]] | Failed |
| 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 / 0315ecd263630a2029e45545f0dcab5c4a15dfa2c95032779ba258bbf0b113cb
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)]
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 if key not in defaults else defaults[key]
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, 3, {'lang': 'en'}]] | [[0, 1, {'lang': 'en', 'weight': 'bold'}], [1, 2, {'lang': 'fr'}], [2, 3, {'lang': 'en'}]] | Failed |
| contract fixture 2 | [[0, 3, {'color': 'red'}]] | [[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 / 2f95042966cefe98fda63a20e770d3f6ac4de270d14b0eefae06c7cff7287a7e
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:42.222757+00:00.
Case digest / 46a2396a7e7464e381cbfa501dae86865438b1cfe9a55ab9d7f1039667505dca