FA-31681 / Keyboard interactions / Open access
Per-switch keyboard scan debounce: Debounced release is published as a press · case 01
The event trace violates the edge name rule and produces incorrect keyboard state or command output.
ROOT CAUSE
Debounced release is published as a press.
VERIFIED REPAIR
Use the contract transition `'down' if value else 'up'` at the edge name fault site; preserve the other state transitions.
Unsuccessful approach: The partial repair changes this transition to 'down', which still violates the model contract on the explicit regression traces.
Case contract
Case [threshold,scans]. Each scan is [time,sorted_pressed_keys] and times increase. A raw transition starts a candidate timer; a candidate becomes stable after continuously present for threshold time including exact boundary. Each scan considers every known or raw key. Emit [key,down_or_up,time] on stable transitions; return emissions plus stable pressed keys. Missing keys are raw up. 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):
threshold,scans=c
stable={}; candidate={}; since={}; output=[]
for now,pressed in scans:
raw=set(pressed)
keys=sorted(set(stable)|set(candidate)|raw)
for key in keys:
value=key in raw
if key not in candidate or candidate[key]!=value:
candidate[key]=value
since[key]=now
if now-since[key]>=threshold and stable.get(key,False)!=value:
stable[key]=value
output.append([key,'up' if value else 'down',now])
return [output,sorted(k for k,v in stable.items() if v)]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('key-debounce scenario 0', solve([[3, []]] * N), [[[], []]] * N)
check('key-debounce scenario 1', solve([[3, [[10, ['A']], [12, ['A']], [13, ['A']], [14, ['A']]]]] * N), [[[['A', 'down', 13]], ['A']]] * N)
check('key-debounce scenario 2', solve([[3, [[10, ['A']], [13, ['A']], [14, []], [17, []]]]] * N), [[[['A', 'down', 13], ['A', 'up', 17]], []]] * N)
check('key-debounce scenario 3', solve([[3, [[10, ['A']], [11, []], [12, ['A']], [14, ['A']], [15, ['A']]]]] * N), [[[['A', 'down', 15]], ['A']]] * N)
check('key-debounce scenario 4', solve([[3, [[10, ['A']], [13, ['A']], [14, ['B']], [17, ['B']]]]] * N), [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] * N)
check('key-debounce scenario 5', solve([[3, [[10, ['A']], [11, []], [14, []]]]] * N), [[[], []]] * N)
check('key-debounce scenario 6', solve([[3, [[10, []], [20, ['A', 'B']], [23, ['A', 'B']], [24, ['B']], [27, ['B']]]]] * N), [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] * N)
check('key-debounce scenario 7', solve([[3, [[10, ['A']], [13, ['A']], [14, []], [15, ['A']], [18, ['A']]]]] * N), [[[['A', 'down', 13]], ['A']]] * 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 |
|---|---|---|---|
| key-debounce scenario 0 | [[[], []]] | [[[], []]] | Passed |
| key-debounce scenario 1 | [[[['A', 'up', 13]], ['A']]] | [[[['A', 'down', 13]], ['A']]] | Failed |
| key-debounce scenario 2 | [[[['A', 'up', 13], ['A', 'down', 17]], []]] | [[[['A', 'down', 13], ['A', 'up', 17]], []]] | Failed |
| key-debounce scenario 3 | [[[['A', 'up', 15]], ['A']]] | [[[['A', 'down', 15]], ['A']]] | Failed |
| key-debounce scenario 4 | [[[['A', 'up', 13], ['A', 'down', 17], ['B', 'up', 17]], ['B']]] | [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] | Failed |
| key-debounce scenario 5 | [[[], []]] | [[[], []]] | Passed |
| key-debounce scenario 6 | [[[['A', 'up', 23], ['B', 'up', 23], ['A', 'down', 27]], ['B']]] | [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] | Failed |
| key-debounce scenario 7 | [[[['A', 'up', 13]], ['A']]] | [[[['A', 'down', 13]], ['A']]] | Failed |
SHA-256 / cc1403422d0dbf724b7de36f1f1bc619b327b1e8fe090f42148fbb5628d7d709
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):
threshold,scans=c
stable={}; candidate={}; since={}; output=[]
for now,pressed in scans:
raw=set(pressed)
keys=sorted(set(stable)|set(candidate)|raw)
for key in keys:
value=key in raw
if key not in candidate or candidate[key]!=value:
candidate[key]=value
since[key]=now
if now-since[key]>=threshold and stable.get(key,False)!=value:
stable[key]=value
output.append([key,'down',now])
return [output,sorted(k for k,v in stable.items() if v)]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('key-debounce scenario 0', solve([[3, []]] * N), [[[], []]] * N)
check('key-debounce scenario 1', solve([[3, [[10, ['A']], [12, ['A']], [13, ['A']], [14, ['A']]]]] * N), [[[['A', 'down', 13]], ['A']]] * N)
check('key-debounce scenario 2', solve([[3, [[10, ['A']], [13, ['A']], [14, []], [17, []]]]] * N), [[[['A', 'down', 13], ['A', 'up', 17]], []]] * N)
check('key-debounce scenario 3', solve([[3, [[10, ['A']], [11, []], [12, ['A']], [14, ['A']], [15, ['A']]]]] * N), [[[['A', 'down', 15]], ['A']]] * N)
check('key-debounce scenario 4', solve([[3, [[10, ['A']], [13, ['A']], [14, ['B']], [17, ['B']]]]] * N), [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] * N)
check('key-debounce scenario 5', solve([[3, [[10, ['A']], [11, []], [14, []]]]] * N), [[[], []]] * N)
check('key-debounce scenario 6', solve([[3, [[10, []], [20, ['A', 'B']], [23, ['A', 'B']], [24, ['B']], [27, ['B']]]]] * N), [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] * N)
check('key-debounce scenario 7', solve([[3, [[10, ['A']], [13, ['A']], [14, []], [15, ['A']], [18, ['A']]]]] * N), [[[['A', 'down', 13]], ['A']]] * 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 |
|---|---|---|---|
| key-debounce scenario 0 | [[[], []]] | [[[], []]] | Passed |
| key-debounce scenario 1 | [[[['A', 'down', 13]], ['A']]] | [[[['A', 'down', 13]], ['A']]] | Passed |
| key-debounce scenario 2 | [[[['A', 'down', 13], ['A', 'down', 17]], []]] | [[[['A', 'down', 13], ['A', 'up', 17]], []]] | Failed |
| key-debounce scenario 3 | [[[['A', 'down', 15]], ['A']]] | [[[['A', 'down', 15]], ['A']]] | Passed |
| key-debounce scenario 4 | [[[['A', 'down', 13], ['A', 'down', 17], ['B', 'down', 17]], ['B']]] | [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] | Failed |
| key-debounce scenario 5 | [[[], []]] | [[[], []]] | Passed |
| key-debounce scenario 6 | [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'down', 27]], ['B']]] | [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] | Failed |
| key-debounce scenario 7 | [[[['A', 'down', 13]], ['A']]] | [[[['A', 'down', 13]], ['A']]] | Passed |
SHA-256 / 0cd1f973e1153725b8200c4d5bf76129590a2e64d96b0bf17f10621895e88177
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):
threshold,scans=c
stable={}; candidate={}; since={}; output=[]
for now,pressed in scans:
raw=set(pressed)
keys=sorted(set(stable)|set(candidate)|raw)
for key in keys:
value=key in raw
if key not in candidate or candidate[key]!=value:
candidate[key]=value
since[key]=now
if now-since[key]>=threshold and stable.get(key,False)!=value:
stable[key]=value
output.append([key,'down' if value else 'up',now])
return [output,sorted(k for k,v in stable.items() if v)]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('key-debounce scenario 0', solve([[3, []]] * N), [[[], []]] * N)
check('key-debounce scenario 1', solve([[3, [[10, ['A']], [12, ['A']], [13, ['A']], [14, ['A']]]]] * N), [[[['A', 'down', 13]], ['A']]] * N)
check('key-debounce scenario 2', solve([[3, [[10, ['A']], [13, ['A']], [14, []], [17, []]]]] * N), [[[['A', 'down', 13], ['A', 'up', 17]], []]] * N)
check('key-debounce scenario 3', solve([[3, [[10, ['A']], [11, []], [12, ['A']], [14, ['A']], [15, ['A']]]]] * N), [[[['A', 'down', 15]], ['A']]] * N)
check('key-debounce scenario 4', solve([[3, [[10, ['A']], [13, ['A']], [14, ['B']], [17, ['B']]]]] * N), [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] * N)
check('key-debounce scenario 5', solve([[3, [[10, ['A']], [11, []], [14, []]]]] * N), [[[], []]] * N)
check('key-debounce scenario 6', solve([[3, [[10, []], [20, ['A', 'B']], [23, ['A', 'B']], [24, ['B']], [27, ['B']]]]] * N), [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] * N)
check('key-debounce scenario 7', solve([[3, [[10, ['A']], [13, ['A']], [14, []], [15, ['A']], [18, ['A']]]]] * N), [[[['A', 'down', 13]], ['A']]] * 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 |
|---|---|---|---|
| key-debounce scenario 0 | [[[], []]] | [[[], []]] | Passed |
| key-debounce scenario 1 | [[[['A', 'down', 13]], ['A']]] | [[[['A', 'down', 13]], ['A']]] | Passed |
| key-debounce scenario 2 | [[[['A', 'down', 13], ['A', 'up', 17]], []]] | [[[['A', 'down', 13], ['A', 'up', 17]], []]] | Passed |
| key-debounce scenario 3 | [[[['A', 'down', 15]], ['A']]] | [[[['A', 'down', 15]], ['A']]] | Passed |
| key-debounce scenario 4 | [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] | [[[['A', 'down', 13], ['A', 'up', 17], ['B', 'down', 17]], ['B']]] | Passed |
| key-debounce scenario 5 | [[[], []]] | [[[], []]] | Passed |
| key-debounce scenario 6 | [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] | [[[['A', 'down', 23], ['B', 'down', 23], ['A', 'up', 27]], ['B']]] | Passed |
| key-debounce scenario 7 | [[[['A', 'down', 13]], ['A']]] | [[[['A', 'down', 13]], ['A']]] | Passed |
SHA-256 / a41cbbca932b1c6a67b6188ff4125f0e29dd181b7435e69222accfa8a0f3f434
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:04.481236+00:00.
Case digest / 47627a67b8ab4340325675ac5be04ab358b0733660dae605fafee1c251b1924c