FA-31971 / Keyboard interactions / Open access
Multi-tap keyboard character commit timing: Timer commits early or fails to commit a character at its deadline · case 01
The event trace violates the tick expiry rule and produces incorrect keyboard state or command output.
ROOT CAUSE
Timer commits early or fails to commit a character at its deadline.
VERIFIED REPAIR
Use the contract transition `elif kind=='tick' and pending is not None and now>=pending[2]:` at the tick expiry fault site; preserve the other state transitions.
Unsuccessful approach: The partial repair changes this transition to elif kind=='tick' and pending is not None:, which still violates the model contract on the explicit regression traces.
Case contract
Case [map,window,events]. Map maps keys to nonempty character strings. Events [kind,value,time]. Valid press cycles the pending same-key character before deadline, otherwise commits previous and starts new. Tick at or past deadline commits. Backspace cancels pending character before deleting committed text. Space commits pending then adds space; cancel drops pending only. Unknown press is ignored. Return committed text and pending [key,index,deadline] or None. 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):
mapping,window,events=c
text=''; pending=None
for kind,value,now in events:
if kind=='press' and value in mapping:
if pending is not None and now>=pending[2]:
text+=mapping[pending[0]][pending[1]]; pending=None
if pending is not None and pending[0]==value:
pending[1]=(pending[1]+1)%len(mapping[value])
pending[2]=now+window
else:
if pending is not None: text+=mapping[pending[0]][pending[1]]
pending=[value,0,now+window]
elif kind=='tick' and pending is not None and now>pending[2]:
text+=mapping[pending[0]][pending[1]]; pending=None
elif kind=='backspace':
if pending is not None: pending=None
else: text=text[:-1]
elif kind=='space':
if pending is not None: text+=mapping[pending[0]][pending[1]]
pending=None; text+=' '
elif kind=='cancel': pending=None
return [text,pending]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('multi-tap-keypad scenario 0', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 11]]]] * N), [['', ['2', 1, 16]]] * N)
check('multi-tap-keypad scenario 1', solve([[{'2': 'abc', '3': 'de'}, 5, []]] * N), [['', None]] * N)
check('multi-tap-keypad scenario 2', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 11], ['press', '2', 12], ['press', '2', 13], ['tick', '', 18]]]] * N), [['a', None]] * N)
check('multi-tap-keypad scenario 3', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 15]]]] * N), [['a', ['2', 0, 20]]] * N)
check('multi-tap-keypad scenario 4', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '3', 12], ['tick', '', 17]]]] * N), [['ad', None]] * N)
check('multi-tap-keypad scenario 5', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['tick', '', 12]]]] * N), [['', ['2', 0, 15]]] * N)
check('multi-tap-keypad scenario 6', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['tick', '', 15], ['press', '3', 16], ['backspace', '', 17]]]] * N), [['a', None]] * N)
check('multi-tap-keypad scenario 7', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '3', 11], ['space', '', 12], ['backspace', '', 13]]]] * N), [['ad', None]] * N)
check('multi-tap-keypad scenario 8', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['space', '', 12]]]] * N), [['a ', None]] * N)
check('multi-tap-keypad scenario 9', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '?', 10], ['backspace', '', 11]]]] * N), [['', None]] * 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 |
|---|---|---|---|
| multi-tap-keypad scenario 0 | [['', ['2', 1, 16]]] | [['', ['2', 1, 16]]] | Passed |
| multi-tap-keypad scenario 1 | [['', None]] | [['', None]] | Passed |
| multi-tap-keypad scenario 2 | [['', ['2', 0, 18]]] | [['a', None]] | Failed |
| multi-tap-keypad scenario 3 | [['a', ['2', 0, 20]]] | [['a', ['2', 0, 20]]] | Passed |
| multi-tap-keypad scenario 4 | [['a', ['3', 0, 17]]] | [['ad', None]] | Failed |
| multi-tap-keypad scenario 5 | [['', ['2', 0, 15]]] | [['', ['2', 0, 15]]] | Passed |
| multi-tap-keypad scenario 6 | [['a', None]] | [['a', None]] | Passed |
| multi-tap-keypad scenario 7 | [['ad', None]] | [['ad', None]] | Passed |
| multi-tap-keypad scenario 8 | [['a ', None]] | [['a ', None]] | Passed |
| multi-tap-keypad scenario 9 | [['', None]] | [['', None]] | Passed |
SHA-256 / 9ff501493b249477d49543ddaf771c7beaf63ab39b0fde07acec743a89764a2e
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):
mapping,window,events=c
text=''; pending=None
for kind,value,now in events:
if kind=='press' and value in mapping:
if pending is not None and now>=pending[2]:
text+=mapping[pending[0]][pending[1]]; pending=None
if pending is not None and pending[0]==value:
pending[1]=(pending[1]+1)%len(mapping[value])
pending[2]=now+window
else:
if pending is not None: text+=mapping[pending[0]][pending[1]]
pending=[value,0,now+window]
elif kind=='tick' and pending is not None:
text+=mapping[pending[0]][pending[1]]; pending=None
elif kind=='backspace':
if pending is not None: pending=None
else: text=text[:-1]
elif kind=='space':
if pending is not None: text+=mapping[pending[0]][pending[1]]
pending=None; text+=' '
elif kind=='cancel': pending=None
return [text,pending]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('multi-tap-keypad scenario 0', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 11]]]] * N), [['', ['2', 1, 16]]] * N)
check('multi-tap-keypad scenario 1', solve([[{'2': 'abc', '3': 'de'}, 5, []]] * N), [['', None]] * N)
check('multi-tap-keypad scenario 2', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 11], ['press', '2', 12], ['press', '2', 13], ['tick', '', 18]]]] * N), [['a', None]] * N)
check('multi-tap-keypad scenario 3', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 15]]]] * N), [['a', ['2', 0, 20]]] * N)
check('multi-tap-keypad scenario 4', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '3', 12], ['tick', '', 17]]]] * N), [['ad', None]] * N)
check('multi-tap-keypad scenario 5', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['tick', '', 12]]]] * N), [['', ['2', 0, 15]]] * N)
check('multi-tap-keypad scenario 6', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['tick', '', 15], ['press', '3', 16], ['backspace', '', 17]]]] * N), [['a', None]] * N)
check('multi-tap-keypad scenario 7', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '3', 11], ['space', '', 12], ['backspace', '', 13]]]] * N), [['ad', None]] * N)
check('multi-tap-keypad scenario 8', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['space', '', 12]]]] * N), [['a ', None]] * N)
check('multi-tap-keypad scenario 9', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '?', 10], ['backspace', '', 11]]]] * N), [['', None]] * 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 |
|---|---|---|---|
| multi-tap-keypad scenario 0 | [['', ['2', 1, 16]]] | [['', ['2', 1, 16]]] | Passed |
| multi-tap-keypad scenario 1 | [['', None]] | [['', None]] | Passed |
| multi-tap-keypad scenario 2 | [['a', None]] | [['a', None]] | Passed |
| multi-tap-keypad scenario 3 | [['a', ['2', 0, 20]]] | [['a', ['2', 0, 20]]] | Passed |
| multi-tap-keypad scenario 4 | [['ad', None]] | [['ad', None]] | Passed |
| multi-tap-keypad scenario 5 | [['a', None]] | [['', ['2', 0, 15]]] | Failed |
| multi-tap-keypad scenario 6 | [['a', None]] | [['a', None]] | Passed |
| multi-tap-keypad scenario 7 | [['ad', None]] | [['ad', None]] | Passed |
| multi-tap-keypad scenario 8 | [['a ', None]] | [['a ', None]] | Passed |
| multi-tap-keypad scenario 9 | [['', None]] | [['', None]] | Passed |
SHA-256 / f1cadc33d78a4641f10d35a37ea6f49354875f633ebe3ae28907f6a7be4ae793
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):
mapping,window,events=c
text=''; pending=None
for kind,value,now in events:
if kind=='press' and value in mapping:
if pending is not None and now>=pending[2]:
text+=mapping[pending[0]][pending[1]]; pending=None
if pending is not None and pending[0]==value:
pending[1]=(pending[1]+1)%len(mapping[value])
pending[2]=now+window
else:
if pending is not None: text+=mapping[pending[0]][pending[1]]
pending=[value,0,now+window]
elif kind=='tick' and pending is not None and now>=pending[2]:
text+=mapping[pending[0]][pending[1]]; pending=None
elif kind=='backspace':
if pending is not None: pending=None
else: text=text[:-1]
elif kind=='space':
if pending is not None: text+=mapping[pending[0]][pending[1]]
pending=None; text+=' '
elif kind=='cancel': pending=None
return [text,pending]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('multi-tap-keypad scenario 0', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 11]]]] * N), [['', ['2', 1, 16]]] * N)
check('multi-tap-keypad scenario 1', solve([[{'2': 'abc', '3': 'de'}, 5, []]] * N), [['', None]] * N)
check('multi-tap-keypad scenario 2', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 11], ['press', '2', 12], ['press', '2', 13], ['tick', '', 18]]]] * N), [['a', None]] * N)
check('multi-tap-keypad scenario 3', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '2', 15]]]] * N), [['a', ['2', 0, 20]]] * N)
check('multi-tap-keypad scenario 4', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '3', 12], ['tick', '', 17]]]] * N), [['ad', None]] * N)
check('multi-tap-keypad scenario 5', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['tick', '', 12]]]] * N), [['', ['2', 0, 15]]] * N)
check('multi-tap-keypad scenario 6', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['tick', '', 15], ['press', '3', 16], ['backspace', '', 17]]]] * N), [['a', None]] * N)
check('multi-tap-keypad scenario 7', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['press', '3', 11], ['space', '', 12], ['backspace', '', 13]]]] * N), [['ad', None]] * N)
check('multi-tap-keypad scenario 8', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '2', 10], ['space', '', 12]]]] * N), [['a ', None]] * N)
check('multi-tap-keypad scenario 9', solve([[{'2': 'abc', '3': 'de'}, 5, [['press', '?', 10], ['backspace', '', 11]]]] * N), [['', None]] * 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 |
|---|---|---|---|
| multi-tap-keypad scenario 0 | [['', ['2', 1, 16]]] | [['', ['2', 1, 16]]] | Passed |
| multi-tap-keypad scenario 1 | [['', None]] | [['', None]] | Passed |
| multi-tap-keypad scenario 2 | [['a', None]] | [['a', None]] | Passed |
| multi-tap-keypad scenario 3 | [['a', ['2', 0, 20]]] | [['a', ['2', 0, 20]]] | Passed |
| multi-tap-keypad scenario 4 | [['ad', None]] | [['ad', None]] | Passed |
| multi-tap-keypad scenario 5 | [['', ['2', 0, 15]]] | [['', ['2', 0, 15]]] | Passed |
| multi-tap-keypad scenario 6 | [['a', None]] | [['a', None]] | Passed |
| multi-tap-keypad scenario 7 | [['ad', None]] | [['ad', None]] | Passed |
| multi-tap-keypad scenario 8 | [['a ', None]] | [['a ', None]] | Passed |
| multi-tap-keypad scenario 9 | [['', None]] | [['', None]] | Passed |
SHA-256 / c49828b5f5b1fdde51b61f28e886a77027aacc96eaa33b82489764363e23d433
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:07.447480+00:00.
Case digest / 81ababeee9febb770cc1819cc22b813c22046beb73eb70776dd969aedff57009