FA-32056 / Keyboard interactions / Open access
Composition replacement against document revisions: A composition update appends to preedit or retains stale provisional content · case 01
The event trace violates the preedit update rule and produces incorrect keyboard state or command output.
ROOT CAUSE
A composition update appends to preedit or retains stale provisional content.
VERIFIED REPAIR
Use the contract transition `pending[3]=text` at the preedit update fault site; preserve the other state transitions.
Unsuccessful approach: The partial repair changes this transition to pending[3]=pending[3], which still violates the model contract on the explicit regression traces.
Case contract
Case [document,revision,events]. Events [kind,a,b,text]. Begin captures valid range [a,b) and current revision with preedit text; update replaces pending preedit; external replaces entire document and increments revision. Commit applies pending replacement only if captured revision still equals current, otherwise counts stale conflict; either path closes pending. Cancel discards pending. Return document, revision, pending [lo,hi,base,text] or None, conflicts. 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):
document,revision,events=c
pending=None; conflicts=0
for kind,a,b,text in events:
if kind=='begin': pending=[a,b,revision,text]
elif kind=='update' and pending is not None: pending[3]+=text
elif kind=='external': document=text; revision+=1
elif kind=='commit' and pending is not None:
lo,hi,base,preedit=pending
if base==revision:
document=document[:lo]+preedit+document[hi:]
revision+=1
else: conflicts+=1
pending=None
elif kind=='cancel': pending=None
return [document,revision,pending,conflicts]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('composition-revision scenario 0', solve([['abcd', 4, []]] * N), [['abcd', 4, None, 0]] * N)
check('composition-revision scenario 1', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['commit', 0, 0, '']]]] * N), [['aXd', 5, None, 0]] * N)
check('composition-revision scenario 2', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['update', 0, 0, 'YZ'], ['commit', 0, 0, '']]]] * N), [['aYZd', 5, None, 0]] * N)
check('composition-revision scenario 3', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['external', 0, 0, 'new'], ['commit', 0, 0, '']]]] * N), [['new', 5, None, 1]] * N)
check('composition-revision scenario 4', solve([['abcd', 4, [['external', 0, 0, 'one'], ['external', 0, 0, 'two']]]] * N), [['two', 6, None, 0]] * N)
check('composition-revision scenario 5', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['external', 0, 0, 'one'], ['external', 0, 0, 'two'], ['commit', 0, 0, ''], ['begin', 0, 1, 'Z'], ['external', 0, 0, 'three'], ['commit', 0, 0, '']]]] * N), [['three', 7, None, 2]] * N)
check('composition-revision scenario 6', solve([['abcd', 4, [['begin', 0, 0, ''], ['cancel', 0, 0, '']]]] * N), [['abcd', 4, None, 0]] * N)
check('composition-revision scenario 7', solve([['abcd', 0, [['begin', 1, 3, 'X'], ['commit', 0, 0, ''], ['commit', 0, 0, '']]]] * N), [['aXd', 1, 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 |
|---|---|---|---|
| composition-revision scenario 0 | [['abcd', 4, None, 0]] | [['abcd', 4, None, 0]] | Passed |
| composition-revision scenario 1 | [['aXd', 5, None, 0]] | [['aXd', 5, None, 0]] | Passed |
| composition-revision scenario 2 | [['aXYZd', 5, None, 0]] | [['aYZd', 5, None, 0]] | Failed |
| composition-revision scenario 3 | [['new', 5, None, 1]] | [['new', 5, None, 1]] | Passed |
| composition-revision scenario 4 | [['two', 6, None, 0]] | [['two', 6, None, 0]] | Passed |
| composition-revision scenario 5 | [['three', 7, None, 2]] | [['three', 7, None, 2]] | Passed |
| composition-revision scenario 6 | [['abcd', 4, None, 0]] | [['abcd', 4, None, 0]] | Passed |
| composition-revision scenario 7 | [['aXd', 1, None, 0]] | [['aXd', 1, None, 0]] | Passed |
SHA-256 / 59194df4d3f9277a688e645e8da289a459687913232fcd1690fb62c2c8e85450
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):
document,revision,events=c
pending=None; conflicts=0
for kind,a,b,text in events:
if kind=='begin': pending=[a,b,revision,text]
elif kind=='update' and pending is not None: pending[3]=pending[3]
elif kind=='external': document=text; revision+=1
elif kind=='commit' and pending is not None:
lo,hi,base,preedit=pending
if base==revision:
document=document[:lo]+preedit+document[hi:]
revision+=1
else: conflicts+=1
pending=None
elif kind=='cancel': pending=None
return [document,revision,pending,conflicts]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('composition-revision scenario 0', solve([['abcd', 4, []]] * N), [['abcd', 4, None, 0]] * N)
check('composition-revision scenario 1', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['commit', 0, 0, '']]]] * N), [['aXd', 5, None, 0]] * N)
check('composition-revision scenario 2', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['update', 0, 0, 'YZ'], ['commit', 0, 0, '']]]] * N), [['aYZd', 5, None, 0]] * N)
check('composition-revision scenario 3', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['external', 0, 0, 'new'], ['commit', 0, 0, '']]]] * N), [['new', 5, None, 1]] * N)
check('composition-revision scenario 4', solve([['abcd', 4, [['external', 0, 0, 'one'], ['external', 0, 0, 'two']]]] * N), [['two', 6, None, 0]] * N)
check('composition-revision scenario 5', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['external', 0, 0, 'one'], ['external', 0, 0, 'two'], ['commit', 0, 0, ''], ['begin', 0, 1, 'Z'], ['external', 0, 0, 'three'], ['commit', 0, 0, '']]]] * N), [['three', 7, None, 2]] * N)
check('composition-revision scenario 6', solve([['abcd', 4, [['begin', 0, 0, ''], ['cancel', 0, 0, '']]]] * N), [['abcd', 4, None, 0]] * N)
check('composition-revision scenario 7', solve([['abcd', 0, [['begin', 1, 3, 'X'], ['commit', 0, 0, ''], ['commit', 0, 0, '']]]] * N), [['aXd', 1, 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 |
|---|---|---|---|
| composition-revision scenario 0 | [['abcd', 4, None, 0]] | [['abcd', 4, None, 0]] | Passed |
| composition-revision scenario 1 | [['aXd', 5, None, 0]] | [['aXd', 5, None, 0]] | Passed |
| composition-revision scenario 2 | [['aXd', 5, None, 0]] | [['aYZd', 5, None, 0]] | Failed |
| composition-revision scenario 3 | [['new', 5, None, 1]] | [['new', 5, None, 1]] | Passed |
| composition-revision scenario 4 | [['two', 6, None, 0]] | [['two', 6, None, 0]] | Passed |
| composition-revision scenario 5 | [['three', 7, None, 2]] | [['three', 7, None, 2]] | Passed |
| composition-revision scenario 6 | [['abcd', 4, None, 0]] | [['abcd', 4, None, 0]] | Passed |
| composition-revision scenario 7 | [['aXd', 1, None, 0]] | [['aXd', 1, None, 0]] | Passed |
SHA-256 / fee446577b101c98f59e7fbb74b2715c8854c3a12210afe00e9d10e1162bec1a
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):
document,revision,events=c
pending=None; conflicts=0
for kind,a,b,text in events:
if kind=='begin': pending=[a,b,revision,text]
elif kind=='update' and pending is not None: pending[3]=text
elif kind=='external': document=text; revision+=1
elif kind=='commit' and pending is not None:
lo,hi,base,preedit=pending
if base==revision:
document=document[:lo]+preedit+document[hi:]
revision+=1
else: conflicts+=1
pending=None
elif kind=='cancel': pending=None
return [document,revision,pending,conflicts]
return [run(c) for c in cases]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('composition-revision scenario 0', solve([['abcd', 4, []]] * N), [['abcd', 4, None, 0]] * N)
check('composition-revision scenario 1', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['commit', 0, 0, '']]]] * N), [['aXd', 5, None, 0]] * N)
check('composition-revision scenario 2', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['update', 0, 0, 'YZ'], ['commit', 0, 0, '']]]] * N), [['aYZd', 5, None, 0]] * N)
check('composition-revision scenario 3', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['external', 0, 0, 'new'], ['commit', 0, 0, '']]]] * N), [['new', 5, None, 1]] * N)
check('composition-revision scenario 4', solve([['abcd', 4, [['external', 0, 0, 'one'], ['external', 0, 0, 'two']]]] * N), [['two', 6, None, 0]] * N)
check('composition-revision scenario 5', solve([['abcd', 4, [['begin', 1, 3, 'X'], ['external', 0, 0, 'one'], ['external', 0, 0, 'two'], ['commit', 0, 0, ''], ['begin', 0, 1, 'Z'], ['external', 0, 0, 'three'], ['commit', 0, 0, '']]]] * N), [['three', 7, None, 2]] * N)
check('composition-revision scenario 6', solve([['abcd', 4, [['begin', 0, 0, ''], ['cancel', 0, 0, '']]]] * N), [['abcd', 4, None, 0]] * N)
check('composition-revision scenario 7', solve([['abcd', 0, [['begin', 1, 3, 'X'], ['commit', 0, 0, ''], ['commit', 0, 0, '']]]] * N), [['aXd', 1, 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 |
|---|---|---|---|
| composition-revision scenario 0 | [['abcd', 4, None, 0]] | [['abcd', 4, None, 0]] | Passed |
| composition-revision scenario 1 | [['aXd', 5, None, 0]] | [['aXd', 5, None, 0]] | Passed |
| composition-revision scenario 2 | [['aYZd', 5, None, 0]] | [['aYZd', 5, None, 0]] | Passed |
| composition-revision scenario 3 | [['new', 5, None, 1]] | [['new', 5, None, 1]] | Passed |
| composition-revision scenario 4 | [['two', 6, None, 0]] | [['two', 6, None, 0]] | Passed |
| composition-revision scenario 5 | [['three', 7, None, 2]] | [['three', 7, None, 2]] | Passed |
| composition-revision scenario 6 | [['abcd', 4, None, 0]] | [['abcd', 4, None, 0]] | Passed |
| composition-revision scenario 7 | [['aXd', 1, None, 0]] | [['aXd', 1, None, 0]] | Passed |
SHA-256 / 1716ae8042814704e7f822e0aae27ac4b9e47d4ef83ad742654827f3399a5289
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:08.227368+00:00.
Case digest / 96ddcffdd1441d058f0f806b3133b3408d45fa555598057ea2abf6ad2f4f1d29