FA-31491 / Keyboard interactions / Open access
Explicit dead-key text composition: A second dead key discards or replaces the pending literal accent · case 01
The event trace violates the successive dead rule and produces incorrect keyboard state or command output.
ROOT CAUSE
A second dead key discards or replaces the pending literal accent.
VERIFIED REPAIR
Use the contract transition `if accent is not None: output.append(accent)` at the successive dead fault site; preserve the other state transitions.
Unsuccessful approach: The partial repair changes this transition to if accent is not None: output.append(value), which still violates the model contract on the explicit regression traces.
Case contract
Case [mapping,events], mapping uses accent+character string keys and string replacements; events [kind,value]. Dead event sets pending accent and flushes a previous accent literally. Text with pending accent maps a pair or emits accent then character; space emits only accent. Backspace cancels pending accent, otherwise emits deletion action. Cancel clears accent; flush emits accent then clears. Return output string chunks and pending accent. 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,events=c
accent=None; output=[]; deletes=0
for kind,value in events:
if kind=='dead':
if accent is not None: pass
accent=value
elif kind=='text':
if accent is None: output.append(value)
else:
if value==' ': output.append(accent)
else: output.append(mapping.get(accent+value,accent+value))
accent=None
elif kind=='backspace':
if accent is not None: accent=None
else: deletes+=1
elif kind=='cancel': accent=None
elif kind=='flush' and accent is not None:
output.append(accent)
accent=None
return [output,accent,deletes]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('dead-key scenario 0', solve([[{}, []]] * N), [[[], None, 0]] * N)
check('dead-key scenario 1', solve([[{}, [['backspace', ''], ['backspace', '']]]] * N), [[[], None, 2]] * N)
check('dead-key scenario 2', solve([[{}, [['dead', '^'], ['backspace', '']]]] * N), [[[], None, 0]] * N)
check('dead-key scenario 3', solve([[{}, [['text', 'word']]]] * N), [[['word'], None, 0]] * N)
check('dead-key scenario 4', solve([[{'^a': 'â'}, [['dead', '^'], ['text', 'a'], ['text', 'b']]]] * N), [[['â', 'b'], None, 0]] * N)
check('dead-key scenario 5', solve([[{}, [['dead', '^'], ['text', 'z']]]] * N), [[['^z'], None, 0]] * N)
check('dead-key scenario 6', solve([[{}, [['dead', '^'], ['text', ' ']]]] * N), [[['^'], None, 0]] * N)
check('dead-key scenario 7', solve([[{}, [['dead', '^'], ['dead', '~'], ['text', 'a']]]] * N), [[['^', '~a'], None, 0]] * N)
check('dead-key scenario 8', solve([[{}, [['dead', '^'], ['backspace', ''], ['text', 'a']]]] * N), [[['a'], None, 0]] * N)
check('dead-key scenario 9', solve([[{}, [['text', 'abc'], ['backspace', ''], ['backspace', '']]]] * N), [[['abc'], None, 2]] * N)
check('dead-key scenario 10', solve([[{}, [['dead', '^'], ['flush', ''], ['flush', '']]]] * N), [[['^'], None, 0]] * N)
check('dead-key scenario 11', solve([[{}, [['dead', '^'], ['cancel', ''], ['text', 'a']]]] * N), [[['a'], None, 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 |
|---|---|---|---|
| dead-key scenario 0 | [[[], None, 0]] | [[[], None, 0]] | Passed |
| dead-key scenario 1 | [[[], None, 2]] | [[[], None, 2]] | Passed |
| dead-key scenario 2 | [[[], None, 0]] | [[[], None, 0]] | Passed |
| dead-key scenario 3 | [[['word'], None, 0]] | [[['word'], None, 0]] | Passed |
| dead-key scenario 4 | [[['â', 'b'], None, 0]] | [[['â', 'b'], None, 0]] | Passed |
| dead-key scenario 5 | [[['^z'], None, 0]] | [[['^z'], None, 0]] | Passed |
| dead-key scenario 6 | [[['^'], None, 0]] | [[['^'], None, 0]] | Passed |
| dead-key scenario 7 | [[['~a'], None, 0]] | [[['^', '~a'], None, 0]] | Failed |
| dead-key scenario 8 | [[['a'], None, 0]] | [[['a'], None, 0]] | Passed |
| dead-key scenario 9 | [[['abc'], None, 2]] | [[['abc'], None, 2]] | Passed |
| dead-key scenario 10 | [[['^'], None, 0]] | [[['^'], None, 0]] | Passed |
| dead-key scenario 11 | [[['a'], None, 0]] | [[['a'], None, 0]] | Passed |
SHA-256 / 8ae871fcf39b82e36ffddb579d3a413a67dcc24bd6d1904bc9be653c6fd69a04
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,events=c
accent=None; output=[]; deletes=0
for kind,value in events:
if kind=='dead':
if accent is not None: output.append(value)
accent=value
elif kind=='text':
if accent is None: output.append(value)
else:
if value==' ': output.append(accent)
else: output.append(mapping.get(accent+value,accent+value))
accent=None
elif kind=='backspace':
if accent is not None: accent=None
else: deletes+=1
elif kind=='cancel': accent=None
elif kind=='flush' and accent is not None:
output.append(accent)
accent=None
return [output,accent,deletes]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('dead-key scenario 0', solve([[{}, []]] * N), [[[], None, 0]] * N)
check('dead-key scenario 1', solve([[{}, [['backspace', ''], ['backspace', '']]]] * N), [[[], None, 2]] * N)
check('dead-key scenario 2', solve([[{}, [['dead', '^'], ['backspace', '']]]] * N), [[[], None, 0]] * N)
check('dead-key scenario 3', solve([[{}, [['text', 'word']]]] * N), [[['word'], None, 0]] * N)
check('dead-key scenario 4', solve([[{'^a': 'â'}, [['dead', '^'], ['text', 'a'], ['text', 'b']]]] * N), [[['â', 'b'], None, 0]] * N)
check('dead-key scenario 5', solve([[{}, [['dead', '^'], ['text', 'z']]]] * N), [[['^z'], None, 0]] * N)
check('dead-key scenario 6', solve([[{}, [['dead', '^'], ['text', ' ']]]] * N), [[['^'], None, 0]] * N)
check('dead-key scenario 7', solve([[{}, [['dead', '^'], ['dead', '~'], ['text', 'a']]]] * N), [[['^', '~a'], None, 0]] * N)
check('dead-key scenario 8', solve([[{}, [['dead', '^'], ['backspace', ''], ['text', 'a']]]] * N), [[['a'], None, 0]] * N)
check('dead-key scenario 9', solve([[{}, [['text', 'abc'], ['backspace', ''], ['backspace', '']]]] * N), [[['abc'], None, 2]] * N)
check('dead-key scenario 10', solve([[{}, [['dead', '^'], ['flush', ''], ['flush', '']]]] * N), [[['^'], None, 0]] * N)
check('dead-key scenario 11', solve([[{}, [['dead', '^'], ['cancel', ''], ['text', 'a']]]] * N), [[['a'], None, 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 |
|---|---|---|---|
| dead-key scenario 0 | [[[], None, 0]] | [[[], None, 0]] | Passed |
| dead-key scenario 1 | [[[], None, 2]] | [[[], None, 2]] | Passed |
| dead-key scenario 2 | [[[], None, 0]] | [[[], None, 0]] | Passed |
| dead-key scenario 3 | [[['word'], None, 0]] | [[['word'], None, 0]] | Passed |
| dead-key scenario 4 | [[['â', 'b'], None, 0]] | [[['â', 'b'], None, 0]] | Passed |
| dead-key scenario 5 | [[['^z'], None, 0]] | [[['^z'], None, 0]] | Passed |
| dead-key scenario 6 | [[['^'], None, 0]] | [[['^'], None, 0]] | Passed |
| dead-key scenario 7 | [[['~', '~a'], None, 0]] | [[['^', '~a'], None, 0]] | Failed |
| dead-key scenario 8 | [[['a'], None, 0]] | [[['a'], None, 0]] | Passed |
| dead-key scenario 9 | [[['abc'], None, 2]] | [[['abc'], None, 2]] | Passed |
| dead-key scenario 10 | [[['^'], None, 0]] | [[['^'], None, 0]] | Passed |
| dead-key scenario 11 | [[['a'], None, 0]] | [[['a'], None, 0]] | Passed |
SHA-256 / ff96849e1a9584f573d2a5d4080fb442630909ab8fe0f31519d4d8376578fb8e
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,events=c
accent=None; output=[]; deletes=0
for kind,value in events:
if kind=='dead':
if accent is not None: output.append(accent)
accent=value
elif kind=='text':
if accent is None: output.append(value)
else:
if value==' ': output.append(accent)
else: output.append(mapping.get(accent+value,accent+value))
accent=None
elif kind=='backspace':
if accent is not None: accent=None
else: deletes+=1
elif kind=='cancel': accent=None
elif kind=='flush' and accent is not None:
output.append(accent)
accent=None
return [output,accent,deletes]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('dead-key scenario 0', solve([[{}, []]] * N), [[[], None, 0]] * N)
check('dead-key scenario 1', solve([[{}, [['backspace', ''], ['backspace', '']]]] * N), [[[], None, 2]] * N)
check('dead-key scenario 2', solve([[{}, [['dead', '^'], ['backspace', '']]]] * N), [[[], None, 0]] * N)
check('dead-key scenario 3', solve([[{}, [['text', 'word']]]] * N), [[['word'], None, 0]] * N)
check('dead-key scenario 4', solve([[{'^a': 'â'}, [['dead', '^'], ['text', 'a'], ['text', 'b']]]] * N), [[['â', 'b'], None, 0]] * N)
check('dead-key scenario 5', solve([[{}, [['dead', '^'], ['text', 'z']]]] * N), [[['^z'], None, 0]] * N)
check('dead-key scenario 6', solve([[{}, [['dead', '^'], ['text', ' ']]]] * N), [[['^'], None, 0]] * N)
check('dead-key scenario 7', solve([[{}, [['dead', '^'], ['dead', '~'], ['text', 'a']]]] * N), [[['^', '~a'], None, 0]] * N)
check('dead-key scenario 8', solve([[{}, [['dead', '^'], ['backspace', ''], ['text', 'a']]]] * N), [[['a'], None, 0]] * N)
check('dead-key scenario 9', solve([[{}, [['text', 'abc'], ['backspace', ''], ['backspace', '']]]] * N), [[['abc'], None, 2]] * N)
check('dead-key scenario 10', solve([[{}, [['dead', '^'], ['flush', ''], ['flush', '']]]] * N), [[['^'], None, 0]] * N)
check('dead-key scenario 11', solve([[{}, [['dead', '^'], ['cancel', ''], ['text', 'a']]]] * N), [[['a'], None, 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 |
|---|---|---|---|
| dead-key scenario 0 | [[[], None, 0]] | [[[], None, 0]] | Passed |
| dead-key scenario 1 | [[[], None, 2]] | [[[], None, 2]] | Passed |
| dead-key scenario 2 | [[[], None, 0]] | [[[], None, 0]] | Passed |
| dead-key scenario 3 | [[['word'], None, 0]] | [[['word'], None, 0]] | Passed |
| dead-key scenario 4 | [[['â', 'b'], None, 0]] | [[['â', 'b'], None, 0]] | Passed |
| dead-key scenario 5 | [[['^z'], None, 0]] | [[['^z'], None, 0]] | Passed |
| dead-key scenario 6 | [[['^'], None, 0]] | [[['^'], None, 0]] | Passed |
| dead-key scenario 7 | [[['^', '~a'], None, 0]] | [[['^', '~a'], None, 0]] | Passed |
| dead-key scenario 8 | [[['a'], None, 0]] | [[['a'], None, 0]] | Passed |
| dead-key scenario 9 | [[['abc'], None, 2]] | [[['abc'], None, 2]] | Passed |
| dead-key scenario 10 | [[['^'], None, 0]] | [[['^'], None, 0]] | Passed |
| dead-key scenario 11 | [[['a'], None, 0]] | [[['a'], None, 0]] | Passed |
SHA-256 / c31a0c79fe9de801c777cb824d40812966653e2190a4e4ead8993702d9211296
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:02.565881+00:00.
Case digest / 44b78081ef311701450032457f2b89c3e82005b9f850ba02e347bb3229dbada0