FA-53676 / Accessibility interaction semantics / Open access
Image recognition labels bypass consent · case 01
Image recognition labels bypass consent.
ROOT CAUSE
The ocr consent decision in the image alternative adapter violates its declared contract.
THE FAILURE
The ocr consent decision in the image alternative adapter violates its declared contract.
Unsuccessful approach: The local repair substitutes if (consent or not alt) and loaded and not broken and ocr: but still mishandles the regression fixtures.
Case contract
Input [decorative,interactive,alt,title,caption,ocr,ocr_consent,filename,loaded,broken]. None alt means absent; empty alt is intentional. Interactive decorative images retain semantics. Source priority is explicit alt (even empty), nonempty caption, title, consented OCR when loaded and not broken; filename is never spoken. Decorative noninteractive images return None. Return [text,source,status] where status is broken, loading, ready with broken highest priority. Normalization strips only surrounding ASCII spaces; OCR is marked inferred.
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):
decorative,interactive,alt,title,caption,ocr,consent,filename,loaded,broken = data
if decorative and not interactive: return None
status = 'broken' if broken else ('ready' if loaded else 'loading')
if alt is not None: return [alt.strip(' '),'alt',status]
if caption: return [caption.strip(' '),'caption',status]
if title: return [title.strip(' '),'title',status]
if loaded and not broken and ocr: return [ocr.strip(' '),'inferred',status]
return ['',None,status]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('decorative inert', solve([True,False,None,'title','caption','ocr',True,'file',True,False],), None)
check('decorative interactive', solve([True,True,' Label '+str(N)+' ','title','caption','ocr',True,'file',True,False],), ['Label '+str(N),'alt','ready'])
check('intentional empty', solve([False,False,'','title','caption','ocr',True,'file',True,False],), ['','alt','ready'])
check('caption precedence', solve([False,False,None,'title',' caption ','ocr',True,'file',True,False],), ['caption','caption','ready'])
check('title only', solve([False,False,None,' title ','','ocr',True,'file',False,False],), ['title','title','loading'])
check('OCR inferred', solve([False,False,None,'','',' OCR '+str(N)+' ',True,'file',True,False],), ['OCR '+str(N),'inferred','ready'])
check('unconsented OCR', solve([False,False,None,'','','ocr',False,'file',True,False],), ['',None,'ready'])
check('loading OCR', solve([False,False,None,'','','ocr',True,'file',False,False],), ['',None,'loading'])
check('broken OCR', solve([False,False,None,'','','ocr',True,'file',True,True],), ['',None,'broken'])
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 |
|---|---|---|---|
| decorative inert | None | None | Passed |
| decorative interactive | ['Label 1', 'alt', 'ready'] | ['Label 1', 'alt', 'ready'] | Passed |
| intentional empty | ['', 'alt', 'ready'] | ['', 'alt', 'ready'] | Passed |
| caption precedence | ['caption', 'caption', 'ready'] | ['caption', 'caption', 'ready'] | Passed |
| title only | ['title', 'title', 'loading'] | ['title', 'title', 'loading'] | Passed |
| OCR inferred | ['OCR 1', 'inferred', 'ready'] | ['OCR 1', 'inferred', 'ready'] | Passed |
| unconsented OCR | ['ocr', 'inferred', 'ready'] | ['', None, 'ready'] | Failed |
| loading OCR | ['', None, 'loading'] | ['', None, 'loading'] | Passed |
| broken OCR | ['', None, 'broken'] | ['', None, 'broken'] | Passed |
SHA-256 / a24a5e2a35e453d1d066fe905452b540d63987e9973f1242298c44b47761853c
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(data):
decorative,interactive,alt,title,caption,ocr,consent,filename,loaded,broken = data
if decorative and not interactive: return None
status = 'broken' if broken else ('ready' if loaded else 'loading')
if alt is not None: return [alt.strip(' '),'alt',status]
if caption: return [caption.strip(' '),'caption',status]
if title: return [title.strip(' '),'title',status]
if (consent or not alt) and loaded and not broken and ocr: return [ocr.strip(' '),'inferred',status]
return ['',None,status]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('decorative inert', solve([True,False,None,'title','caption','ocr',True,'file',True,False],), None)
check('decorative interactive', solve([True,True,' Label '+str(N)+' ','title','caption','ocr',True,'file',True,False],), ['Label '+str(N),'alt','ready'])
check('intentional empty', solve([False,False,'','title','caption','ocr',True,'file',True,False],), ['','alt','ready'])
check('caption precedence', solve([False,False,None,'title',' caption ','ocr',True,'file',True,False],), ['caption','caption','ready'])
check('title only', solve([False,False,None,' title ','','ocr',True,'file',False,False],), ['title','title','loading'])
check('OCR inferred', solve([False,False,None,'','',' OCR '+str(N)+' ',True,'file',True,False],), ['OCR '+str(N),'inferred','ready'])
check('unconsented OCR', solve([False,False,None,'','','ocr',False,'file',True,False],), ['',None,'ready'])
check('loading OCR', solve([False,False,None,'','','ocr',True,'file',False,False],), ['',None,'loading'])
check('broken OCR', solve([False,False,None,'','','ocr',True,'file',True,True],), ['',None,'broken'])
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 |
|---|---|---|---|
| decorative inert | None | None | Passed |
| decorative interactive | ['Label 1', 'alt', 'ready'] | ['Label 1', 'alt', 'ready'] | Passed |
| intentional empty | ['', 'alt', 'ready'] | ['', 'alt', 'ready'] | Passed |
| caption precedence | ['caption', 'caption', 'ready'] | ['caption', 'caption', 'ready'] | Passed |
| title only | ['title', 'title', 'loading'] | ['title', 'title', 'loading'] | Passed |
| OCR inferred | ['OCR 1', 'inferred', 'ready'] | ['OCR 1', 'inferred', 'ready'] | Passed |
| unconsented OCR | ['ocr', 'inferred', 'ready'] | ['', None, 'ready'] | Failed |
| loading OCR | ['', None, 'loading'] | ['', None, 'loading'] | Passed |
| broken OCR | ['', None, 'broken'] | ['', None, 'broken'] | Passed |
SHA-256 / 8657204dbd0ff385af11dbda02864dc5112b31a2ea1b5a54e58e916409b7458d
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 9 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗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:41.410638+00:00.
Case digest / 36b3f228656e3c18f42a92d670f0e9e725ef607a72801c9fa939ad79d2186110