FA-31351 / Keyboard interactions / Open access
Sticky modifier latch lifecycle: Unlocking one modifier erases unrelated latches or retains a false entry · case 01
The event trace violates the unlock removal rule and produces incorrect keyboard state or command output.
ROOT CAUSE
Unlocking one modifier erases unrelated latches or retains a false entry.
VERIFIED REPAIR
Use the contract transition `else: latches.pop(key,None)` at the unlock removal fault site; preserve the other state transitions.
Unsuccessful approach: The partial repair changes this transition to else: latches[key]=0, which still violates the model contract on the explicit regression traces.
Case contract
Events [kind,key]. Tap of modifier cycles absent -> once -> locked -> absent. Modifier down/up sets physical state independently. Character emits [key,sorted effective modifiers] then consumes all once latches but preserves locked and physical modifiers. Cancel clears latches only; blur clears both. Return emitted events, latches and physical state. 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):
latches={}; physical=set(); out=[]
for kind,key in c:
if kind=='tap':
state=latches.get(key,0)
next_state=(state+1)%3
if next_state: latches[key]=next_state
else: latches.clear()
elif kind=='down': physical.add(key)
elif kind=='up': physical.discard(key)
elif kind=='char':
effective=physical | set(latches)
out.append([key,sorted(effective)])
latches={k:v for k,v in latches.items() if v==2}
elif kind=='cancel': latches.clear()
elif kind=='blur':
latches.clear(); physical.clear()
return [out,sorted([[k,v] for k,v in latches.items()]),sorted(physical)]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('sticky-modifiers scenario 0', solve([[]] * N), [[[], [], []]] * N)
check('sticky-modifiers scenario 1', solve([[['tap', 'Shift'], ['char', 'A'], ['char', 'B']]] * N), [[[['A', ['Shift']], ['B', []]], [], []]] * N)
check('sticky-modifiers scenario 2', solve([[['tap', 'Shift'], ['tap', 'Shift'], ['char', 'A'], ['char', 'B']]] * N), [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] * N)
check('sticky-modifiers scenario 3', solve([[['tap', 'Shift'], ['tap', 'Shift'], ['tap', 'Alt'], ['tap', 'Shift'], ['char', 'A']]] * N), [[[['A', ['Alt']]], [], []]] * N)
check('sticky-modifiers scenario 4', solve([[['down', 'Control'], ['down', 'Alt'], ['down', 'Alt'], ['char', 'A']]] * N), [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] * N)
check('sticky-modifiers scenario 5', solve([[['down', 'Control'], ['down', 'Alt'], ['up', 'Alt'], ['char', 'A']]] * N), [[[['A', ['Control']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 6', solve([[['down', 'Control'], ['tap', 'Shift'], ['char', 'A']]] * N), [[[['A', ['Control', 'Shift']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 7', solve([[['down', 'Control'], ['tap', 'Shift'], ['cancel', ''], ['char', 'A']]] * N), [[[['A', ['Control']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 8', solve([[['down', 'Control'], ['tap', 'Shift'], ['blur', '']]] * N), [[[], [], []]] * 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 |
|---|---|---|---|
| sticky-modifiers scenario 0 | [[[], [], []]] | [[[], [], []]] | Passed |
| sticky-modifiers scenario 1 | [[[['A', ['Shift']], ['B', []]], [], []]] | [[[['A', ['Shift']], ['B', []]], [], []]] | Passed |
| sticky-modifiers scenario 2 | [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] | [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] | Passed |
| sticky-modifiers scenario 3 | [[[['A', []]], [], []]] | [[[['A', ['Alt']]], [], []]] | Failed |
| sticky-modifiers scenario 4 | [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] | [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] | Passed |
| sticky-modifiers scenario 5 | [[[['A', ['Control']]], [], ['Control']]] | [[[['A', ['Control']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 6 | [[[['A', ['Control', 'Shift']]], [], ['Control']]] | [[[['A', ['Control', 'Shift']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 7 | [[[['A', ['Control']]], [], ['Control']]] | [[[['A', ['Control']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 8 | [[[], [], []]] | [[[], [], []]] | Passed |
SHA-256 / c8d4a26117f18ecfe863660cf238146922647e91f0c4425dbf41776207f4c819
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):
latches={}; physical=set(); out=[]
for kind,key in c:
if kind=='tap':
state=latches.get(key,0)
next_state=(state+1)%3
if next_state: latches[key]=next_state
else: latches[key]=0
elif kind=='down': physical.add(key)
elif kind=='up': physical.discard(key)
elif kind=='char':
effective=physical | set(latches)
out.append([key,sorted(effective)])
latches={k:v for k,v in latches.items() if v==2}
elif kind=='cancel': latches.clear()
elif kind=='blur':
latches.clear(); physical.clear()
return [out,sorted([[k,v] for k,v in latches.items()]),sorted(physical)]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('sticky-modifiers scenario 0', solve([[]] * N), [[[], [], []]] * N)
check('sticky-modifiers scenario 1', solve([[['tap', 'Shift'], ['char', 'A'], ['char', 'B']]] * N), [[[['A', ['Shift']], ['B', []]], [], []]] * N)
check('sticky-modifiers scenario 2', solve([[['tap', 'Shift'], ['tap', 'Shift'], ['char', 'A'], ['char', 'B']]] * N), [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] * N)
check('sticky-modifiers scenario 3', solve([[['tap', 'Shift'], ['tap', 'Shift'], ['tap', 'Alt'], ['tap', 'Shift'], ['char', 'A']]] * N), [[[['A', ['Alt']]], [], []]] * N)
check('sticky-modifiers scenario 4', solve([[['down', 'Control'], ['down', 'Alt'], ['down', 'Alt'], ['char', 'A']]] * N), [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] * N)
check('sticky-modifiers scenario 5', solve([[['down', 'Control'], ['down', 'Alt'], ['up', 'Alt'], ['char', 'A']]] * N), [[[['A', ['Control']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 6', solve([[['down', 'Control'], ['tap', 'Shift'], ['char', 'A']]] * N), [[[['A', ['Control', 'Shift']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 7', solve([[['down', 'Control'], ['tap', 'Shift'], ['cancel', ''], ['char', 'A']]] * N), [[[['A', ['Control']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 8', solve([[['down', 'Control'], ['tap', 'Shift'], ['blur', '']]] * N), [[[], [], []]] * 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 |
|---|---|---|---|
| sticky-modifiers scenario 0 | [[[], [], []]] | [[[], [], []]] | Passed |
| sticky-modifiers scenario 1 | [[[['A', ['Shift']], ['B', []]], [], []]] | [[[['A', ['Shift']], ['B', []]], [], []]] | Passed |
| sticky-modifiers scenario 2 | [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] | [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] | Passed |
| sticky-modifiers scenario 3 | [[[['A', ['Alt', 'Shift']]], [], []]] | [[[['A', ['Alt']]], [], []]] | Failed |
| sticky-modifiers scenario 4 | [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] | [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] | Passed |
| sticky-modifiers scenario 5 | [[[['A', ['Control']]], [], ['Control']]] | [[[['A', ['Control']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 6 | [[[['A', ['Control', 'Shift']]], [], ['Control']]] | [[[['A', ['Control', 'Shift']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 7 | [[[['A', ['Control']]], [], ['Control']]] | [[[['A', ['Control']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 8 | [[[], [], []]] | [[[], [], []]] | Passed |
SHA-256 / 59fe619549e4f048632753d0f0398fc6f2801bc4b9fe08b595340c0fe447df74
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):
latches={}; physical=set(); out=[]
for kind,key in c:
if kind=='tap':
state=latches.get(key,0)
next_state=(state+1)%3
if next_state: latches[key]=next_state
else: latches.pop(key,None)
elif kind=='down': physical.add(key)
elif kind=='up': physical.discard(key)
elif kind=='char':
effective=physical | set(latches)
out.append([key,sorted(effective)])
latches={k:v for k,v in latches.items() if v==2}
elif kind=='cancel': latches.clear()
elif kind=='blur':
latches.clear(); physical.clear()
return [out,sorted([[k,v] for k,v in latches.items()]),sorted(physical)]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('sticky-modifiers scenario 0', solve([[]] * N), [[[], [], []]] * N)
check('sticky-modifiers scenario 1', solve([[['tap', 'Shift'], ['char', 'A'], ['char', 'B']]] * N), [[[['A', ['Shift']], ['B', []]], [], []]] * N)
check('sticky-modifiers scenario 2', solve([[['tap', 'Shift'], ['tap', 'Shift'], ['char', 'A'], ['char', 'B']]] * N), [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] * N)
check('sticky-modifiers scenario 3', solve([[['tap', 'Shift'], ['tap', 'Shift'], ['tap', 'Alt'], ['tap', 'Shift'], ['char', 'A']]] * N), [[[['A', ['Alt']]], [], []]] * N)
check('sticky-modifiers scenario 4', solve([[['down', 'Control'], ['down', 'Alt'], ['down', 'Alt'], ['char', 'A']]] * N), [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] * N)
check('sticky-modifiers scenario 5', solve([[['down', 'Control'], ['down', 'Alt'], ['up', 'Alt'], ['char', 'A']]] * N), [[[['A', ['Control']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 6', solve([[['down', 'Control'], ['tap', 'Shift'], ['char', 'A']]] * N), [[[['A', ['Control', 'Shift']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 7', solve([[['down', 'Control'], ['tap', 'Shift'], ['cancel', ''], ['char', 'A']]] * N), [[[['A', ['Control']]], [], ['Control']]] * N)
check('sticky-modifiers scenario 8', solve([[['down', 'Control'], ['tap', 'Shift'], ['blur', '']]] * N), [[[], [], []]] * 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 |
|---|---|---|---|
| sticky-modifiers scenario 0 | [[[], [], []]] | [[[], [], []]] | Passed |
| sticky-modifiers scenario 1 | [[[['A', ['Shift']], ['B', []]], [], []]] | [[[['A', ['Shift']], ['B', []]], [], []]] | Passed |
| sticky-modifiers scenario 2 | [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] | [[[['A', ['Shift']], ['B', ['Shift']]], [['Shift', 2]], []]] | Passed |
| sticky-modifiers scenario 3 | [[[['A', ['Alt']]], [], []]] | [[[['A', ['Alt']]], [], []]] | Passed |
| sticky-modifiers scenario 4 | [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] | [[[['A', ['Alt', 'Control']]], [], ['Alt', 'Control']]] | Passed |
| sticky-modifiers scenario 5 | [[[['A', ['Control']]], [], ['Control']]] | [[[['A', ['Control']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 6 | [[[['A', ['Control', 'Shift']]], [], ['Control']]] | [[[['A', ['Control', 'Shift']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 7 | [[[['A', ['Control']]], [], ['Control']]] | [[[['A', ['Control']]], [], ['Control']]] | Passed |
| sticky-modifiers scenario 8 | [[[], [], []]] | [[[], [], []]] | Passed |
SHA-256 / 44669353d0bf76253c49ddc9a65ea6e0f914c3a6987af48e8f08857354bc93bb
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:42:01.230864+00:00.
Case digest / 53945fc7fd5fd3747f7869724816367bc1ce7365de537f8240197d752e612ab9