FAILURE MAP
← Case archive

FA-8851 / Selection controls / Open access

Radio group selection ownership: Activating a different radio fails to change selection · case 01

Activating a different radio fails to change selection.

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

ROOT CAUSE

The activation replacement operation uses `selected = selected` where the contract requires `selected = target`.

VERIFIED REPAIR

Implement the activation replacement operation as `selected = target`.

Unsuccessful approach: Toggling off the current radio violates exclusive selection semantics.

Case contract

Radio activation replaces selection with an existing enabled option and never toggles it off; required groups cannot clear; selected removal uses first remaining option only when required.

Why this case matters

A deterministic model of radio group selection ownership; this isolates one interface invariant without requiring a browser.

1 / The failure

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

N = 1
observations = []
def solve(options, selected, target, required, disabled, event):
    if event == 'remove':
        options = [x for x in options if x != target]
        if selected not in options: selected = options[0] if required and options else None
    elif event == 'activate':
        if target in options and target not in disabled: selected = selected
    elif event == 'clear' and not required: selected = None
    return (options, selected)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('remove other', solve(['a','b','c'], 'a', 'b', False, [], 'remove'), (['a', 'c'], 'a'))
check('required removal', solve(['a','b','c'], 'a', 'a', True, [], 'remove'), (['b', 'c'], 'b'))
check('unknown', solve(['a','b'], 'a', 'x', False, [], 'activate'), (['a', 'b'], 'a'))
check('disabled', solve(['a','b'], 'a', 'b', False, ['b'], 'activate'), (['a', 'b'], 'a'))
check('required clear', solve(['a','b'], 'a', None, True, [], 'clear'), (['a', 'b'], 'a'))
check('optional clear', solve(['a','b'], 'a', None, False, [], 'clear'), (['a', 'b'], None))
check('activate', solve(['a','b'], 'a', 'b', False, [], 'activate'), (['a', 'b'], 'b'))
check('reactivate', solve(['a','b'], 'a', 'a', False, [], 'activate'), (['a', 'b'], 'a'))
check('parameterized radio options', solve(list(range(N+1)),0,N,False,[],'activate'), (list(range(N+1)),N))
for repetition in range(N):
    check('repeat reactivate', solve(['a','b'], 'a', 'a', False, [], 'activate'), (['a', 'b'], 'a'))
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
remove other[['a', 'c'], 'a'][['a', 'c'], 'a']Passed
required removal[['b', 'c'], 'b'][['b', 'c'], 'b']Passed
unknown[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
disabled[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
required clear[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
optional clear[['a', 'b'], None][['a', 'b'], None]Passed
activate[['a', 'b'], 'a'][['a', 'b'], 'b']Failed
reactivate[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
parameterized radio options[[0, 1], 0][[0, 1], 1]Failed
repeat reactivate[['a', 'b'], 'a'][['a', 'b'], 'a']Passed

SHA-256 / 7b3ce797c2aebc02a8de898924c1011397f93405bb700c27e49512c4f9321f76

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(options, selected, target, required, disabled, event):
    if event == 'remove':
        options = [x for x in options if x != target]
        if selected not in options: selected = options[0] if required and options else None
    elif event == 'activate':
        if target in options and target not in disabled: selected = None if selected == target else target
    elif event == 'clear' and not required: selected = None
    return (options, selected)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('remove other', solve(['a','b','c'], 'a', 'b', False, [], 'remove'), (['a', 'c'], 'a'))
check('required removal', solve(['a','b','c'], 'a', 'a', True, [], 'remove'), (['b', 'c'], 'b'))
check('unknown', solve(['a','b'], 'a', 'x', False, [], 'activate'), (['a', 'b'], 'a'))
check('disabled', solve(['a','b'], 'a', 'b', False, ['b'], 'activate'), (['a', 'b'], 'a'))
check('required clear', solve(['a','b'], 'a', None, True, [], 'clear'), (['a', 'b'], 'a'))
check('optional clear', solve(['a','b'], 'a', None, False, [], 'clear'), (['a', 'b'], None))
check('activate', solve(['a','b'], 'a', 'b', False, [], 'activate'), (['a', 'b'], 'b'))
check('reactivate', solve(['a','b'], 'a', 'a', False, [], 'activate'), (['a', 'b'], 'a'))
check('parameterized radio options', solve(list(range(N+1)),0,N,False,[],'activate'), (list(range(N+1)),N))
for repetition in range(N):
    check('repeat reactivate', solve(['a','b'], 'a', 'a', False, [], 'activate'), (['a', 'b'], 'a'))
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
remove other[['a', 'c'], 'a'][['a', 'c'], 'a']Passed
required removal[['b', 'c'], 'b'][['b', 'c'], 'b']Passed
unknown[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
disabled[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
required clear[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
optional clear[['a', 'b'], None][['a', 'b'], None]Passed
activate[['a', 'b'], 'b'][['a', 'b'], 'b']Passed
reactivate[['a', 'b'], None][['a', 'b'], 'a']Failed
parameterized radio options[[0, 1], 1][[0, 1], 1]Passed
repeat reactivate[['a', 'b'], None][['a', 'b'], 'a']Failed

SHA-256 / cb7e6e0dcec79b87e64f7377c10c590c3586f63d4c4f05d67079dcb8b6fb0a8d

3 / The verified repair

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

N = 1
observations = []
def solve(options, selected, target, required, disabled, event):
    if event == 'remove':
        options = [x for x in options if x != target]
        if selected not in options: selected = options[0] if required and options else None
    elif event == 'activate':
        if target in options and target not in disabled: selected = target
    elif event == 'clear' and not required: selected = None
    return (options, selected)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('remove other', solve(['a','b','c'], 'a', 'b', False, [], 'remove'), (['a', 'c'], 'a'))
check('required removal', solve(['a','b','c'], 'a', 'a', True, [], 'remove'), (['b', 'c'], 'b'))
check('unknown', solve(['a','b'], 'a', 'x', False, [], 'activate'), (['a', 'b'], 'a'))
check('disabled', solve(['a','b'], 'a', 'b', False, ['b'], 'activate'), (['a', 'b'], 'a'))
check('required clear', solve(['a','b'], 'a', None, True, [], 'clear'), (['a', 'b'], 'a'))
check('optional clear', solve(['a','b'], 'a', None, False, [], 'clear'), (['a', 'b'], None))
check('activate', solve(['a','b'], 'a', 'b', False, [], 'activate'), (['a', 'b'], 'b'))
check('reactivate', solve(['a','b'], 'a', 'a', False, [], 'activate'), (['a', 'b'], 'a'))
check('parameterized radio options', solve(list(range(N+1)),0,N,False,[],'activate'), (list(range(N+1)),N))
for repetition in range(N):
    check('repeat reactivate', solve(['a','b'], 'a', 'a', False, [], 'activate'), (['a', 'b'], 'a'))
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
remove other[['a', 'c'], 'a'][['a', 'c'], 'a']Passed
required removal[['b', 'c'], 'b'][['b', 'c'], 'b']Passed
unknown[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
disabled[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
required clear[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
optional clear[['a', 'b'], None][['a', 'b'], None]Passed
activate[['a', 'b'], 'b'][['a', 'b'], 'b']Passed
reactivate[['a', 'b'], 'a'][['a', 'b'], 'a']Passed
parameterized radio options[[0, 1], 1][[0, 1], 1]Passed
repeat reactivate[['a', 'b'], 'a'][['a', 'b'], 'a']Passed

SHA-256 / 4f8f9a9b0059c204bdbca082b20c90cecc2a74313620caf4bb5bf20aea9fae2e

Verification & scope

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

Case digest / 92fe1deb1287748730da867316a68c8ec9c31c5ca561f122ab2909cf8a210db1