FAILURE MAP
← Case archive

FA-53856 / Accessibility interaction semantics / Open access

Disabled hyperlinks remain reachable through text interfaces · case 01

Disabled hyperlinks remain reachable through text interfaces.

Verified by executionVariant 1 · 6 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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 fixtureActualExpectedOutcome
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