FA-54286 / Accessibility interaction semantics / Open access
Repeated declarations duplicate inverse relation descriptors · case 01
Repeated declarations duplicate inverse relation descriptors.
ROOT CAUSE
The inverse dedup decision in the inverse relations adapter violates its declared contract.
VERIFIED REPAIR
Apply the exact contract at the inverse dedup decision: if backward not in result[target]:
Unsuccessful approach: The local repair substitutes if not result[target] or result[target][-1] != forward: 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':'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 True: 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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'], ['controlled_by', '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 / 87b4623c14aa909cb6da3e1974530cf2a4da515bbf840b3accbfd4788a625750
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':'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 not result[target] or result[target][-1] != forward: 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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'], ['controlled_by', '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 / f9e20ee5401d2f31853393a7fc14b29fb21190997179d7473d808335d43c1fbe
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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.952549+00:00.
Case digest / ac66971d807494fd0c691638f12ebe42b028f791c65e5d1093ebee825263b79e