FA-8856 / Client state / Open access
Controlled and uncontrolled input ownership: Empty controlled values are mistaken for uncontrolled state · case 01
Empty controlled values are mistaken for uncontrolled state.
ROOT CAUSE
The falsy control operation uses `bool(prop)` where the contract requires `prop is not None`.
VERIFIED REPAIR
Implement the falsy control operation as `prop is not None`.
Unsuccessful approach: Treating empty as uncontrolled also misclassifies None as controlled.
Case contract
None alone signals uncontrolled; defaults initialize only on mount/reset; controlled values stay prop-owned while proposed changes are emitted; uncontrolled changes update local state.
Why this case matters
A deterministic model of controlled and uncontrolled input 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(prop, local, default, event, incoming, mounted):
controlled = bool(prop)
if not mounted: local = default
if event == 'input':
if not controlled: local = incoming
notification = incoming
else: notification = None
if event == 'reset' and not controlled: local = default
visible = prop if controlled else local
return (visible, local, notification)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('empty controlled', solve('', 'draft', 'default', 'none', None, True), ('', 'draft', None))
check('mounted', solve(None, 'edited', 'default', 'none', None, True), ('edited', 'edited', None))
check('mount', solve(None, None, 'default', 'none', None, False), ('default', 'default', None))
check('controlled event', solve('old', 'local', 'default', 'input', 'new', True), ('old', 'local', 'new'))
check('uncontrolled event', solve(None, 'local', 'default', 'input', 'new', True), ('new', 'new', 'new'))
check('controlled reset', solve('old', 'local', 'default', 'reset', None, True), ('old', 'local', None))
check('uncontrolled reset', solve(None, 'local', 'default', 'reset', None, True), ('default', 'default', None))
check('parameterized proposed value', solve('old','local','default','input',str(N),True), ('old','local',str(N)))
for repetition in range(N):
check('repeat uncontrolled reset', solve(None, 'local', 'default', 'reset', None, True), ('default', 'default', None))
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 |
|---|---|---|---|
| empty controlled | ['draft', 'draft', None] | ['', 'draft', None] | Failed |
| mounted | ['edited', 'edited', None] | ['edited', 'edited', None] | Passed |
| mount | ['default', 'default', None] | ['default', 'default', None] | Passed |
| controlled event | ['old', 'local', 'new'] | ['old', 'local', 'new'] | Passed |
| uncontrolled event | ['new', 'new', 'new'] | ['new', 'new', 'new'] | Passed |
| controlled reset | ['old', 'local', None] | ['old', 'local', None] | Passed |
| uncontrolled reset | ['default', 'default', None] | ['default', 'default', None] | Passed |
| parameterized proposed value | ['old', 'local', '1'] | ['old', 'local', '1'] | Passed |
| repeat uncontrolled reset | ['default', 'default', None] | ['default', 'default', None] | Passed |
SHA-256 / 976b4e9a7b1b87ebcf853283007280b26c1605ba53361827ba458981f29b7338
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(prop, local, default, event, incoming, mounted):
controlled = prop != ""
if not mounted: local = default
if event == 'input':
if not controlled: local = incoming
notification = incoming
else: notification = None
if event == 'reset' and not controlled: local = default
visible = prop if controlled else local
return (visible, local, notification)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('empty controlled', solve('', 'draft', 'default', 'none', None, True), ('', 'draft', None))
check('mounted', solve(None, 'edited', 'default', 'none', None, True), ('edited', 'edited', None))
check('mount', solve(None, None, 'default', 'none', None, False), ('default', 'default', None))
check('controlled event', solve('old', 'local', 'default', 'input', 'new', True), ('old', 'local', 'new'))
check('uncontrolled event', solve(None, 'local', 'default', 'input', 'new', True), ('new', 'new', 'new'))
check('controlled reset', solve('old', 'local', 'default', 'reset', None, True), ('old', 'local', None))
check('uncontrolled reset', solve(None, 'local', 'default', 'reset', None, True), ('default', 'default', None))
check('parameterized proposed value', solve('old','local','default','input',str(N),True), ('old','local',str(N)))
for repetition in range(N):
check('repeat uncontrolled reset', solve(None, 'local', 'default', 'reset', None, True), ('default', 'default', None))
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 |
|---|---|---|---|
| empty controlled | ['draft', 'draft', None] | ['', 'draft', None] | Failed |
| mounted | [None, 'edited', None] | ['edited', 'edited', None] | Failed |
| mount | [None, 'default', None] | ['default', 'default', None] | Failed |
| controlled event | ['old', 'local', 'new'] | ['old', 'local', 'new'] | Passed |
| uncontrolled event | [None, 'local', 'new'] | ['new', 'new', 'new'] | Failed |
| controlled reset | ['old', 'local', None] | ['old', 'local', None] | Passed |
| uncontrolled reset | [None, 'local', None] | ['default', 'default', None] | Failed |
| parameterized proposed value | ['old', 'local', '1'] | ['old', 'local', '1'] | Passed |
| repeat uncontrolled reset | [None, 'local', None] | ['default', 'default', None] | Failed |
SHA-256 / 97098303ac7b59f74ea902fb19c23349e569cb82fd0dfeec06694299d840d4e9
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(prop, local, default, event, incoming, mounted):
controlled = prop is not None
if not mounted: local = default
if event == 'input':
if not controlled: local = incoming
notification = incoming
else: notification = None
if event == 'reset' and not controlled: local = default
visible = prop if controlled else local
return (visible, local, notification)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('empty controlled', solve('', 'draft', 'default', 'none', None, True), ('', 'draft', None))
check('mounted', solve(None, 'edited', 'default', 'none', None, True), ('edited', 'edited', None))
check('mount', solve(None, None, 'default', 'none', None, False), ('default', 'default', None))
check('controlled event', solve('old', 'local', 'default', 'input', 'new', True), ('old', 'local', 'new'))
check('uncontrolled event', solve(None, 'local', 'default', 'input', 'new', True), ('new', 'new', 'new'))
check('controlled reset', solve('old', 'local', 'default', 'reset', None, True), ('old', 'local', None))
check('uncontrolled reset', solve(None, 'local', 'default', 'reset', None, True), ('default', 'default', None))
check('parameterized proposed value', solve('old','local','default','input',str(N),True), ('old','local',str(N)))
for repetition in range(N):
check('repeat uncontrolled reset', solve(None, 'local', 'default', 'reset', None, True), ('default', 'default', None))
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 |
|---|---|---|---|
| empty controlled | ['', 'draft', None] | ['', 'draft', None] | Passed |
| mounted | ['edited', 'edited', None] | ['edited', 'edited', None] | Passed |
| mount | ['default', 'default', None] | ['default', 'default', None] | Passed |
| controlled event | ['old', 'local', 'new'] | ['old', 'local', 'new'] | Passed |
| uncontrolled event | ['new', 'new', 'new'] | ['new', 'new', 'new'] | Passed |
| controlled reset | ['old', 'local', None] | ['old', 'local', None] | Passed |
| uncontrolled reset | ['default', 'default', None] | ['default', 'default', None] | Passed |
| parameterized proposed value | ['old', 'local', '1'] | ['old', 'local', '1'] | Passed |
| repeat uncontrolled reset | ['default', 'default', None] | ['default', 'default', None] | Passed |
SHA-256 / 044bf1425e9ccf3192b50c30d160246d7effd44fbafd16c7e31c2db164649187
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:25.016714+00:00.
Case digest / 2c92806f9205af830035d1d29a2e1cae5dffda8c983ea449ef5dda21d385bdbe