FAILURE MAP
← Case archive

FA-31521 / Keyboard interactions / Open access

Explicit dead-key text composition: Completed text composition leaves a pending accent for the next character · case 01

The event trace violates the consume accent rule and produces incorrect keyboard state or command output.

Verified by executionVariant 1 · 12 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Completed text composition leaves a pending accent for the next character.

VERIFIED REPAIR

Use the contract transition `accent=None elif kind=='backspace'` at the consume accent fault site; preserve the other state transitions.

Unsuccessful approach: The partial repair changes this transition to pass elif kind=='backspace', 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: 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=value
            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 fixtureActualExpectedOutcome
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[[['â', 'ab'], 'b', 0]][[['â', 'b'], None, 0]]Failed
dead-key scenario 5[[['^z'], 'z', 0]][[['^z'], None, 0]]Failed
dead-key scenario 6[[['^'], ' ', 0]][[['^'], None, 0]]Failed
dead-key scenario 7[[['^', '~a'], 'a', 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 / 5652a31c674cc7925b0c975eb64db47fc22ed71a8dd38743ce89e839aace7e29

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(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))
                    pass
            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 fixtureActualExpectedOutcome
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'], '^', 0]][[['â', 'b'], None, 0]]Failed
dead-key scenario 5[[['^z'], '^', 0]][[['^z'], None, 0]]Failed
dead-key scenario 6[[['^'], '^', 0]][[['^'], None, 0]]Failed
dead-key scenario 7[[['^', '~a'], '~', 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 / 50670e151316e0dca4a33cea4844c440bea5a9bd24e4ff1e40094d7ebc73f197

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 fixtureActualExpectedOutcome
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.936217+00:00.

Case digest / bfd6779a4e1188958785d0017d6f2aa26cc70d0e1b5529b290a61b557610907d