FA-8836 / Selection controls / Open access
Radio group selection ownership: Removing the selected required option leaves the group unselected · case 01
Removing the selected required option leaves the group unselected.
ROOT CAUSE
The required fallback operation uses `None` where the contract requires `options[0] if required and options else None`.
VERIFIED REPAIR
Implement the required fallback operation as `options[0] if required and options else None`.
Unsuccessful approach: Choosing the last option violates deterministic first-choice fallback.
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 = 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| remove other | [['a', 'c'], 'a'] | [['a', 'c'], 'a'] | Passed |
| required removal | [['b', 'c'], None] | [['b', 'c'], 'b'] | Failed |
| 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 / 4872f519b977386696dd3c71cf07e0ede5a9db7dd3ef51b6147c4dbc5240b10c
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[-1] 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| remove other | [['a', 'c'], 'a'] | [['a', 'c'], 'a'] | Passed |
| required removal | [['b', 'c'], 'c'] | [['b', 'c'], 'b'] | Failed |
| 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 / 14e37a32f09831aa32dadf1df98ca0ed9b0ea761e7cbe49c847b3d3f5e9b1d85
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| 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.852625+00:00.
Case digest / b5abc3b8e10cbe1f185baf7aade238c09e564e1414bab082ad28bf55546d5530