FA-31036 / Keyboard interactions / Open access
Release activated command binding: Owner departure removes a token named after the owner or clears other owners · case 01
The event trace violates the departure remove rule and produces incorrect keyboard state or command output.
ROOT CAUSE
Owner departure removes a token named after the owner or clears other owners.
VERIFIED REPAIR
Use the contract transition `for k in dropped: pending.pop(k)` at the departure remove fault site; preserve the other state transitions.
Unsuccessful approach: The partial repair changes this transition to for k in dropped: pending.clear(), which still violates the model contract on the explicit regression traces.
Case contract
Events [kind,key,owner]. Down arms a key for its owner; repeated down preserves the original owner. Up emits key only for matching key and owner then always disarms that physical key. Cancel clears all pending keys; owner-left clears that owner. Return emitted key-owner pairs and sorted pending pairs. Inputs are finite ordered event traces; return the stated deterministic state. Batch entries are independent. N varies the number of independent input transactions.
Why this case matters
Controlled keyboard event processing model for debugging application event logic.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(cases):
def run(c):
pending={}; emitted=[]; cancelled=0; unmatched=0
for kind,key,owner in c:
if kind=='down':
if key not in pending: pending[key]=owner
elif kind=='up':
if key in pending and pending[key]==owner:
emitted.append([key,owner])
else: unmatched+=1
pending.pop(key,None)
elif kind=='cancel':
cancelled+=len(pending)
pending.clear()
elif kind=='owner-left':
dropped=[k for k,v in pending.items() if v==owner]
cancelled+=len(dropped)
for k in dropped: pending.pop(owner,None)
return [emitted,sorted([[k,v] for k,v in pending.items()]),cancelled,unmatched]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('release-binding scenario 0', solve([[]] * N), [[[], [], 0, 0]] * N)
check('release-binding scenario 1', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
check('release-binding scenario 2', solve([[['up', 'A', 'one'], ['up', 'B', 'one']]] * N), [[[], [], 0, 2]] * N)
check('release-binding scenario 3', solve([[['down', 'A', 'one'], ['down', 'A', 'two'], ['up', 'A', 'two']]] * N), [[[], [], 0, 1]] * N)
check('release-binding scenario 4', solve([[['down', 'A', 'one'], ['up', 'A', 'one'], ['up', 'A', 'one']]] * N), [[[['A', 'one']], [], 0, 1]] * N)
check('release-binding scenario 5', solve([[['down', 'A', 'one'], ['down', 'B', 'two'], ['up', 'A', 'one']]] * N), [[[['A', 'one']], [['B', 'two']], 0, 0]] * N)
check('release-binding scenario 6', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['cancel', '', ''], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
check('release-binding scenario 7', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['down', 'C', 'two'], ['owner-left', '', 'one']]] * N), [[[], [['C', 'two']], 2, 0]] * N)
check('release-binding scenario 8', solve([[['down', 'A', 'one'], ['owner-left', '', 'two']]] * N), [[[], [['A', 'one']], 0, 0]] * N)
check('release-binding scenario 9', solve([[['down', 'A', 'one'], ['cancel', '', ''], ['down', 'B', 'two'], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
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 |
|---|---|---|---|
| release-binding scenario 0 | [[[], [], 0, 0]] | [[[], [], 0, 0]] | Passed |
| release-binding scenario 1 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
| release-binding scenario 2 | [[[], [], 0, 2]] | [[[], [], 0, 2]] | Passed |
| release-binding scenario 3 | [[[], [], 0, 1]] | [[[], [], 0, 1]] | Passed |
| release-binding scenario 4 | [[[['A', 'one']], [], 0, 1]] | [[[['A', 'one']], [], 0, 1]] | Passed |
| release-binding scenario 5 | [[[['A', 'one']], [['B', 'two']], 0, 0]] | [[[['A', 'one']], [['B', 'two']], 0, 0]] | Passed |
| release-binding scenario 6 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
| release-binding scenario 7 | [[[], [['A', 'one'], ['B', 'one'], ['C', 'two']], 2, 0]] | [[[], [['C', 'two']], 2, 0]] | Failed |
| release-binding scenario 8 | [[[], [['A', 'one']], 0, 0]] | [[[], [['A', 'one']], 0, 0]] | Passed |
| release-binding scenario 9 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
SHA-256 / 5b58b272fb4097c8d7b5199725f7af7661fb29928f99419b3435caf83f18b697
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(cases):
def run(c):
pending={}; emitted=[]; cancelled=0; unmatched=0
for kind,key,owner in c:
if kind=='down':
if key not in pending: pending[key]=owner
elif kind=='up':
if key in pending and pending[key]==owner:
emitted.append([key,owner])
else: unmatched+=1
pending.pop(key,None)
elif kind=='cancel':
cancelled+=len(pending)
pending.clear()
elif kind=='owner-left':
dropped=[k for k,v in pending.items() if v==owner]
cancelled+=len(dropped)
for k in dropped: pending.clear()
return [emitted,sorted([[k,v] for k,v in pending.items()]),cancelled,unmatched]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('release-binding scenario 0', solve([[]] * N), [[[], [], 0, 0]] * N)
check('release-binding scenario 1', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
check('release-binding scenario 2', solve([[['up', 'A', 'one'], ['up', 'B', 'one']]] * N), [[[], [], 0, 2]] * N)
check('release-binding scenario 3', solve([[['down', 'A', 'one'], ['down', 'A', 'two'], ['up', 'A', 'two']]] * N), [[[], [], 0, 1]] * N)
check('release-binding scenario 4', solve([[['down', 'A', 'one'], ['up', 'A', 'one'], ['up', 'A', 'one']]] * N), [[[['A', 'one']], [], 0, 1]] * N)
check('release-binding scenario 5', solve([[['down', 'A', 'one'], ['down', 'B', 'two'], ['up', 'A', 'one']]] * N), [[[['A', 'one']], [['B', 'two']], 0, 0]] * N)
check('release-binding scenario 6', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['cancel', '', ''], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
check('release-binding scenario 7', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['down', 'C', 'two'], ['owner-left', '', 'one']]] * N), [[[], [['C', 'two']], 2, 0]] * N)
check('release-binding scenario 8', solve([[['down', 'A', 'one'], ['owner-left', '', 'two']]] * N), [[[], [['A', 'one']], 0, 0]] * N)
check('release-binding scenario 9', solve([[['down', 'A', 'one'], ['cancel', '', ''], ['down', 'B', 'two'], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
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 |
|---|---|---|---|
| release-binding scenario 0 | [[[], [], 0, 0]] | [[[], [], 0, 0]] | Passed |
| release-binding scenario 1 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
| release-binding scenario 2 | [[[], [], 0, 2]] | [[[], [], 0, 2]] | Passed |
| release-binding scenario 3 | [[[], [], 0, 1]] | [[[], [], 0, 1]] | Passed |
| release-binding scenario 4 | [[[['A', 'one']], [], 0, 1]] | [[[['A', 'one']], [], 0, 1]] | Passed |
| release-binding scenario 5 | [[[['A', 'one']], [['B', 'two']], 0, 0]] | [[[['A', 'one']], [['B', 'two']], 0, 0]] | Passed |
| release-binding scenario 6 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
| release-binding scenario 7 | [[[], [], 2, 0]] | [[[], [['C', 'two']], 2, 0]] | Failed |
| release-binding scenario 8 | [[[], [['A', 'one']], 0, 0]] | [[[], [['A', 'one']], 0, 0]] | Passed |
| release-binding scenario 9 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
SHA-256 / 253abd37bfdd729bd5d4d501872afdba37fa10cc3231e7aecae470f85d8aa7d0
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(cases):
def run(c):
pending={}; emitted=[]; cancelled=0; unmatched=0
for kind,key,owner in c:
if kind=='down':
if key not in pending: pending[key]=owner
elif kind=='up':
if key in pending and pending[key]==owner:
emitted.append([key,owner])
else: unmatched+=1
pending.pop(key,None)
elif kind=='cancel':
cancelled+=len(pending)
pending.clear()
elif kind=='owner-left':
dropped=[k for k,v in pending.items() if v==owner]
cancelled+=len(dropped)
for k in dropped: pending.pop(k)
return [emitted,sorted([[k,v] for k,v in pending.items()]),cancelled,unmatched]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('release-binding scenario 0', solve([[]] * N), [[[], [], 0, 0]] * N)
check('release-binding scenario 1', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
check('release-binding scenario 2', solve([[['up', 'A', 'one'], ['up', 'B', 'one']]] * N), [[[], [], 0, 2]] * N)
check('release-binding scenario 3', solve([[['down', 'A', 'one'], ['down', 'A', 'two'], ['up', 'A', 'two']]] * N), [[[], [], 0, 1]] * N)
check('release-binding scenario 4', solve([[['down', 'A', 'one'], ['up', 'A', 'one'], ['up', 'A', 'one']]] * N), [[[['A', 'one']], [], 0, 1]] * N)
check('release-binding scenario 5', solve([[['down', 'A', 'one'], ['down', 'B', 'two'], ['up', 'A', 'one']]] * N), [[[['A', 'one']], [['B', 'two']], 0, 0]] * N)
check('release-binding scenario 6', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['cancel', '', ''], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
check('release-binding scenario 7', solve([[['down', 'A', 'one'], ['down', 'B', 'one'], ['down', 'C', 'two'], ['owner-left', '', 'one']]] * N), [[[], [['C', 'two']], 2, 0]] * N)
check('release-binding scenario 8', solve([[['down', 'A', 'one'], ['owner-left', '', 'two']]] * N), [[[], [['A', 'one']], 0, 0]] * N)
check('release-binding scenario 9', solve([[['down', 'A', 'one'], ['cancel', '', ''], ['down', 'B', 'two'], ['cancel', '', '']]] * N), [[[], [], 2, 0]] * N)
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 |
|---|---|---|---|
| release-binding scenario 0 | [[[], [], 0, 0]] | [[[], [], 0, 0]] | Passed |
| release-binding scenario 1 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
| release-binding scenario 2 | [[[], [], 0, 2]] | [[[], [], 0, 2]] | Passed |
| release-binding scenario 3 | [[[], [], 0, 1]] | [[[], [], 0, 1]] | Passed |
| release-binding scenario 4 | [[[['A', 'one']], [], 0, 1]] | [[[['A', 'one']], [], 0, 1]] | Passed |
| release-binding scenario 5 | [[[['A', 'one']], [['B', 'two']], 0, 0]] | [[[['A', 'one']], [['B', 'two']], 0, 0]] | Passed |
| release-binding scenario 6 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
| release-binding scenario 7 | [[[], [['C', 'two']], 2, 0]] | [[[], [['C', 'two']], 2, 0]] | Passed |
| release-binding scenario 8 | [[[], [['A', 'one']], 0, 0]] | [[[], [['A', 'one']], 0, 0]] | Passed |
| release-binding scenario 9 | [[[], [], 2, 0]] | [[[], [], 2, 0]] | Passed |
SHA-256 / e21d0e53af3f7e82145e8398182479d83ec93a586f50b2fb877e540de2c6a875
Verification & scope
Offline stipulated event model, not a browser implementation or web standard conformance claim. 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:41:58.374337+00:00.
Case digest / f887fb5fe43347936270fe203649ca74c5da652b0c58c7a9276d208ba1118521