FA-53856 / Accessibility interaction semantics / Open access
Disabled hyperlinks remain reachable through text interfaces · case 01
Disabled hyperlinks remain reachable through text interfaces.
ROOT CAUSE
The link enabled decision in the hyperlink spans adapter violates its declared contract.
VERIFIED REPAIR
Apply the exact contract at the link enabled decision: not enabled or not url
Unsuccessful approach: The local repair substitutes not enabled and not url but still mishandles the regression fixtures.
Case contract
Input [text_length,links,offset] where links [id,start,end,url,enabled]. Admit only nonempty URL, enabled and nonempty interval after clamping. Sort by start then shorter interval then input order; dedupe IDs after sorting. Query offset resolves the first matching half-open span, or None. Return [ordered descriptors,hit_id]. URLs remain exact including fragments; IDs are retained even when URL is shared.
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,links,offset = data
valid = []
for i,(ident,start,end,url,enabled) in enumerate(links):
if not url: continue
start,end = max(0,start),min(length,end)
if start >= end: continue
valid.append((start,end-start,i,ident,end,url))
valid.sort(key=lambda x:(x[0],x[1],x[2]))
seen = set()
rows = []
for start,width,i,ident,end,url in valid:
if ident in seen: continue
seen.add(ident)
rows.append([ident,start,end,url])
hit = next((ident for ident,start,end,url in rows if start <= offset < end),None)
return [rows,hit]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,[['wide',N,N+4,'/a#x',True],['small',N,N+2,'/a#y',True]],N+1],), [[['small',N,N+2,'/a#y'],['wide',N,N+4,'/a#x']],'small'])
check('contract fixture 2', solve([5,[['a',-3,2,'/a',True],['b',2,8,'/b',True]],2],), [[['a',0,2,'/a'],['b',2,5,'/b']],'b'])
check('contract fixture 3', solve([5,[['a',1,1,'/a',True],['b',4,2,'/b',True],['c',0,3,'',True],['d',0,3,'/d',False]],0],), [[],None])
check('contract fixture 4', solve([6,[['a',3,6,'later',True],['a',0,2,'early',True]],1],), [[['a',0,2,'early']],'a'])
check('contract fixture 5', solve([3,[['a',0,3,'/same',True],['b',0,3,'/same',True]],3],), [[['a',0,3,'/same'],['b',0,3,'/same']],None])
check('contract fixture 6', solve([0,[],0],), [[],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 | [[['small', 1, 3, '/a#y'], ['wide', 1, 5, '/a#x']], 'small'] | [[['small', 1, 3, '/a#y'], ['wide', 1, 5, '/a#x']], 'small'] | Passed |
| contract fixture 2 | [[['a', 0, 2, '/a'], ['b', 2, 5, '/b']], 'b'] | [[['a', 0, 2, '/a'], ['b', 2, 5, '/b']], 'b'] | Passed |
| contract fixture 3 | [[['d', 0, 3, '/d']], 'd'] | [[], None] | Failed |
| contract fixture 4 | [[['a', 0, 2, 'early']], 'a'] | [[['a', 0, 2, 'early']], 'a'] | Passed |
| contract fixture 5 | [[['a', 0, 3, '/same'], ['b', 0, 3, '/same']], None] | [[['a', 0, 3, '/same'], ['b', 0, 3, '/same']], None] | Passed |
| contract fixture 6 | [[], None] | [[], None] | Passed |
SHA-256 / 4ae936525b536237c8b7f6f2ed5badf6e8c0912dc9fbac3b572344dd87140870
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,links,offset = data
valid = []
for i,(ident,start,end,url,enabled) in enumerate(links):
if not enabled and not url: continue
start,end = max(0,start),min(length,end)
if start >= end: continue
valid.append((start,end-start,i,ident,end,url))
valid.sort(key=lambda x:(x[0],x[1],x[2]))
seen = set()
rows = []
for start,width,i,ident,end,url in valid:
if ident in seen: continue
seen.add(ident)
rows.append([ident,start,end,url])
hit = next((ident for ident,start,end,url in rows if start <= offset < end),None)
return [rows,hit]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,[['wide',N,N+4,'/a#x',True],['small',N,N+2,'/a#y',True]],N+1],), [[['small',N,N+2,'/a#y'],['wide',N,N+4,'/a#x']],'small'])
check('contract fixture 2', solve([5,[['a',-3,2,'/a',True],['b',2,8,'/b',True]],2],), [[['a',0,2,'/a'],['b',2,5,'/b']],'b'])
check('contract fixture 3', solve([5,[['a',1,1,'/a',True],['b',4,2,'/b',True],['c',0,3,'',True],['d',0,3,'/d',False]],0],), [[],None])
check('contract fixture 4', solve([6,[['a',3,6,'later',True],['a',0,2,'early',True]],1],), [[['a',0,2,'early']],'a'])
check('contract fixture 5', solve([3,[['a',0,3,'/same',True],['b',0,3,'/same',True]],3],), [[['a',0,3,'/same'],['b',0,3,'/same']],None])
check('contract fixture 6', solve([0,[],0],), [[],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 | [[['small', 1, 3, '/a#y'], ['wide', 1, 5, '/a#x']], 'small'] | [[['small', 1, 3, '/a#y'], ['wide', 1, 5, '/a#x']], 'small'] | Passed |
| contract fixture 2 | [[['a', 0, 2, '/a'], ['b', 2, 5, '/b']], 'b'] | [[['a', 0, 2, '/a'], ['b', 2, 5, '/b']], 'b'] | Passed |
| contract fixture 3 | [[['c', 0, 3, ''], ['d', 0, 3, '/d']], 'c'] | [[], None] | Failed |
| contract fixture 4 | [[['a', 0, 2, 'early']], 'a'] | [[['a', 0, 2, 'early']], 'a'] | Passed |
| contract fixture 5 | [[['a', 0, 3, '/same'], ['b', 0, 3, '/same']], None] | [[['a', 0, 3, '/same'], ['b', 0, 3, '/same']], None] | Passed |
| contract fixture 6 | [[], None] | [[], None] | Passed |
SHA-256 / f63f92b102e6951b0571c0152214ca3989923db4c633d8e7a55999bb3e26738b
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
length,links,offset = data
valid = []
for i,(ident,start,end,url,enabled) in enumerate(links):
if not enabled or not url: continue
start,end = max(0,start),min(length,end)
if start >= end: continue
valid.append((start,end-start,i,ident,end,url))
valid.sort(key=lambda x:(x[0],x[1],x[2]))
seen = set()
rows = []
for start,width,i,ident,end,url in valid:
if ident in seen: continue
seen.add(ident)
rows.append([ident,start,end,url])
hit = next((ident for ident,start,end,url in rows if start <= offset < end),None)
return [rows,hit]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([N+5,[['wide',N,N+4,'/a#x',True],['small',N,N+2,'/a#y',True]],N+1],), [[['small',N,N+2,'/a#y'],['wide',N,N+4,'/a#x']],'small'])
check('contract fixture 2', solve([5,[['a',-3,2,'/a',True],['b',2,8,'/b',True]],2],), [[['a',0,2,'/a'],['b',2,5,'/b']],'b'])
check('contract fixture 3', solve([5,[['a',1,1,'/a',True],['b',4,2,'/b',True],['c',0,3,'',True],['d',0,3,'/d',False]],0],), [[],None])
check('contract fixture 4', solve([6,[['a',3,6,'later',True],['a',0,2,'early',True]],1],), [[['a',0,2,'early']],'a'])
check('contract fixture 5', solve([3,[['a',0,3,'/same',True],['b',0,3,'/same',True]],3],), [[['a',0,3,'/same'],['b',0,3,'/same']],None])
check('contract fixture 6', solve([0,[],0],), [[],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 | [[['small', 1, 3, '/a#y'], ['wide', 1, 5, '/a#x']], 'small'] | [[['small', 1, 3, '/a#y'], ['wide', 1, 5, '/a#x']], 'small'] | Passed |
| contract fixture 2 | [[['a', 0, 2, '/a'], ['b', 2, 5, '/b']], 'b'] | [[['a', 0, 2, '/a'], ['b', 2, 5, '/b']], 'b'] | Passed |
| contract fixture 3 | [[], None] | [[], None] | Passed |
| contract fixture 4 | [[['a', 0, 2, 'early']], 'a'] | [[['a', 0, 2, 'early']], 'a'] | Passed |
| contract fixture 5 | [[['a', 0, 3, '/same'], ['b', 0, 3, '/same']], None] | [[['a', 0, 3, '/same'], ['b', 0, 3, '/same']], None] | Passed |
| contract fixture 6 | [[], None] | [[], None] | Passed |
SHA-256 / f4654d835f55847af12997f87b94c7f2e1def26a29178e6b84b9e32d343f7cde
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.910523+00:00.
Case digest / a167dd95fee6aaff4ae1187d9b98b100aad40b2349cbd51e753132872734f2e0