FAILURE MAP
← Case archive

FA-54261 / Accessibility interaction semantics / Open access

Controlled objects report forward control instead of controller relation · case 01

Controlled objects report forward control instead of controller relation.

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

ROOT CAUSE

The control inverse decision in the inverse relations adapter violates its declared contract.

VERIFIED REPAIR

Apply the exact contract at the control inverse decision: 'controls':'controlled_by'

Unsuccessful approach: The local repair substitutes 'controls':'details_for' but still mishandles the regression fixtures.

Case contract

Input [node_ids,relations] relations [source,kind,target]. Kind label_for maps inverse labelled_by, description_for maps described_by, controls maps controlled_by, details maps details_for. Unknown types ignored. Resolve only existing distinct nodes. For each node output direct and inverse [kind,other_id] pairs, deduping while preserving relation encounter order. Direct is appended before inverse. Nodes with no links are retained in input order; input node IDs are unique. Forward and reverse kinds remain distinct even for reciprocal declarations.

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):
    nodes,relations = data
    inverse = {'label_for':'labelled_by','description_for':'described_by','controls':'controls','details':'details_for'}
    result = {node:[] for node in nodes}
    for source,kind,target in relations:
        if kind not in inverse or source not in result or target not in result or source == target: continue
        forward = [kind,target]
        backward = [inverse[kind],source]
        if forward not in result[source]: result[source].append(forward)
        if backward not in result[target]: result[target].append(backward)
    return [[node,result[node]] for node in nodes]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([['a','b',str(N),'alone'],[['a','label_for','b'],['a','description_for','b'],['b','controls',str(N)],['a','details',str(N)]]],), [['a',[['label_for','b'],['description_for','b'],['details',str(N)]]],['b',[['labelled_by','a'],['described_by','a'],['controls',str(N)]]],[str(N),[['controlled_by','b'],['details_for','a']]],['alone',[]]])
check('contract fixture 2', solve([['a','b'],[['a','controls','b'],['b','controls','a']]],), [['a',[['controls','b'],['controlled_by','b']]],['b',[['controlled_by','a'],['controls','a']]]])
check('contract fixture 3', solve([['a','b'],[['a','controls','b'],['a','controls','b']]],), [['a',[['controls','b']]],['b',[['controlled_by','a']]]])
check('contract fixture 4', solve([['a'],[['a','controls','a'],['a','unknown','a'],['a','controls','missing'],['missing','details','a']]],), [['a',[]]])
check('contract fixture 5', solve([['z','a'],[]],), [['z',[]],['a',[]]])
check('contract fixture 6', solve([[],[]],), [])
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[['a', [['label_for', 'b'], ['description_for', 'b'], ['details', '1']]], ['b', [['labelled_by', 'a'], ['described_by', 'a'], ['controls', '1']]], ['1', [['controls', 'b'], ['details_for', 'a']]], ['alone', []]][['a', [['label_for', 'b'], ['description_for', 'b'], ['details', '1']]], ['b', [['labelled_by', 'a'], ['described_by', 'a'], ['controls', '1']]], ['1', [['controlled_by', 'b'], ['details_for', 'a']]], ['alone', []]]Failed
contract fixture 2[['a', [['controls', 'b']]], ['b', [['controls', 'a']]]][['a', [['controls', 'b'], ['controlled_by', 'b']]], ['b', [['controlled_by', 'a'], ['controls', 'a']]]]Failed
contract fixture 3[['a', [['controls', 'b']]], ['b', [['controls', 'a']]]][['a', [['controls', 'b']]], ['b', [['controlled_by', 'a']]]]Failed
contract fixture 4[['a', []]][['a', []]]Passed
contract fixture 5[['z', []], ['a', []]][['z', []], ['a', []]]Passed
contract fixture 6[][]Passed

SHA-256 / b4a03fd733cb92cfe0589d4d3a70028dd4a806b84b4995c9cda8973892e4ffa9

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(data):
    nodes,relations = data
    inverse = {'label_for':'labelled_by','description_for':'described_by','controls':'details_for','details':'details_for'}
    result = {node:[] for node in nodes}
    for source,kind,target in relations:
        if kind not in inverse or source not in result or target not in result or source == target: continue
        forward = [kind,target]
        backward = [inverse[kind],source]
        if forward not in result[source]: result[source].append(forward)
        if backward not in result[target]: result[target].append(backward)
    return [[node,result[node]] for node in nodes]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([['a','b',str(N),'alone'],[['a','label_for','b'],['a','description_for','b'],['b','controls',str(N)],['a','details',str(N)]]],), [['a',[['label_for','b'],['description_for','b'],['details',str(N)]]],['b',[['labelled_by','a'],['described_by','a'],['controls',str(N)]]],[str(N),[['controlled_by','b'],['details_for','a']]],['alone',[]]])
check('contract fixture 2', solve([['a','b'],[['a','controls','b'],['b','controls','a']]],), [['a',[['controls','b'],['controlled_by','b']]],['b',[['controlled_by','a'],['controls','a']]]])
check('contract fixture 3', solve([['a','b'],[['a','controls','b'],['a','controls','b']]],), [['a',[['controls','b']]],['b',[['controlled_by','a']]]])
check('contract fixture 4', solve([['a'],[['a','controls','a'],['a','unknown','a'],['a','controls','missing'],['missing','details','a']]],), [['a',[]]])
check('contract fixture 5', solve([['z','a'],[]],), [['z',[]],['a',[]]])
check('contract fixture 6', solve([[],[]],), [])
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[['a', [['label_for', 'b'], ['description_for', 'b'], ['details', '1']]], ['b', [['labelled_by', 'a'], ['described_by', 'a'], ['controls', '1']]], ['1', [['details_for', 'b'], ['details_for', 'a']]], ['alone', []]][['a', [['label_for', 'b'], ['description_for', 'b'], ['details', '1']]], ['b', [['labelled_by', 'a'], ['described_by', 'a'], ['controls', '1']]], ['1', [['controlled_by', 'b'], ['details_for', 'a']]], ['alone', []]]Failed
contract fixture 2[['a', [['controls', 'b'], ['details_for', 'b']]], ['b', [['details_for', 'a'], ['controls', 'a']]]][['a', [['controls', 'b'], ['controlled_by', 'b']]], ['b', [['controlled_by', 'a'], ['controls', 'a']]]]Failed
contract fixture 3[['a', [['controls', 'b']]], ['b', [['details_for', 'a']]]][['a', [['controls', 'b']]], ['b', [['controlled_by', 'a']]]]Failed
contract fixture 4[['a', []]][['a', []]]Passed
contract fixture 5[['z', []], ['a', []]][['z', []], ['a', []]]Passed
contract fixture 6[][]Passed

SHA-256 / 755466d5d0caeba84952c6c55d8c31d55bf169e608e0bdeb846f754c640a72de

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(data):
    nodes,relations = data
    inverse = {'label_for':'labelled_by','description_for':'described_by','controls':'controlled_by','details':'details_for'}
    result = {node:[] for node in nodes}
    for source,kind,target in relations:
        if kind not in inverse or source not in result or target not in result or source == target: continue
        forward = [kind,target]
        backward = [inverse[kind],source]
        if forward not in result[source]: result[source].append(forward)
        if backward not in result[target]: result[target].append(backward)
    return [[node,result[node]] for node in nodes]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('contract fixture 1', solve([['a','b',str(N),'alone'],[['a','label_for','b'],['a','description_for','b'],['b','controls',str(N)],['a','details',str(N)]]],), [['a',[['label_for','b'],['description_for','b'],['details',str(N)]]],['b',[['labelled_by','a'],['described_by','a'],['controls',str(N)]]],[str(N),[['controlled_by','b'],['details_for','a']]],['alone',[]]])
check('contract fixture 2', solve([['a','b'],[['a','controls','b'],['b','controls','a']]],), [['a',[['controls','b'],['controlled_by','b']]],['b',[['controlled_by','a'],['controls','a']]]])
check('contract fixture 3', solve([['a','b'],[['a','controls','b'],['a','controls','b']]],), [['a',[['controls','b']]],['b',[['controlled_by','a']]]])
check('contract fixture 4', solve([['a'],[['a','controls','a'],['a','unknown','a'],['a','controls','missing'],['missing','details','a']]],), [['a',[]]])
check('contract fixture 5', solve([['z','a'],[]],), [['z',[]],['a',[]]])
check('contract fixture 6', solve([[],[]],), [])
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[['a', [['label_for', 'b'], ['description_for', 'b'], ['details', '1']]], ['b', [['labelled_by', 'a'], ['described_by', 'a'], ['controls', '1']]], ['1', [['controlled_by', 'b'], ['details_for', 'a']]], ['alone', []]][['a', [['label_for', 'b'], ['description_for', 'b'], ['details', '1']]], ['b', [['labelled_by', 'a'], ['described_by', 'a'], ['controls', '1']]], ['1', [['controlled_by', 'b'], ['details_for', 'a']]], ['alone', []]]Passed
contract fixture 2[['a', [['controls', 'b'], ['controlled_by', 'b']]], ['b', [['controlled_by', 'a'], ['controls', 'a']]]][['a', [['controls', 'b'], ['controlled_by', 'b']]], ['b', [['controlled_by', 'a'], ['controls', 'a']]]]Passed
contract fixture 3[['a', [['controls', 'b']]], ['b', [['controlled_by', 'a']]]][['a', [['controls', 'b']]], ['b', [['controlled_by', 'a']]]]Passed
contract fixture 4[['a', []]][['a', []]]Passed
contract fixture 5[['z', []], ['a', []]][['z', []], ['a', []]]Passed
contract fixture 6[][]Passed

SHA-256 / a7a1ee56bc82131067c11d7fc7cb9ef84f303f0df332749a712bb01ea09f9d15

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:46.640644+00:00.

Case digest / 6417dd0f0c29497120ae27cf3a13ff5c493219c02d4a3c4134747ff909b6199e