Spurious undo/retrace erases words; next chord merges with stale state #1

Open
opened 2026-07-04 14:07:18 +08:00 by afiqzudinhadi · 0 comments
afiqzudinhadi commented 2026-07-04 14:07:18 +08:00 (Migrated from github.com)

Observed on hardware (corne, v4 engine, both dicts):

  • Occasionally a stroke triggers what looks like an undo/delete out of nowhere and erases multiple previous words.
  • The next key press after such an event merges into a chord with something stale (combos with keys that are no longer held).

Likely causes to investigate:

  1. Fingerprint false-accepts on longest-match window probes. Every stroke probes multi-stroke windows (previous strokes + new). Windows that are not real entries still pass the 4-bit fingerprint + membership gate ~3-4% of the time → bogus multi-stroke "match" fires a retrace that erases the previous translations and emits an unrelated entry. With several probes per stroke this compounds to a per-stroke wrong-fire rate in the 10-20% range.
    • Planned mitigation (from the v4 design spec): resurrect the per-dict prefix Bloom filters (~24 KB, left half has budget) and gate multi-stroke window probes on "this stroke can start a multi-stroke entry". Kills ~95% of bogus probes.
  2. keys_held / chord state desync across halves. If a release event is lost or reordered over BLE, keys_held never reaches zero, so the next press merges into the stale chord. Needs a defensive resync (e.g. clear chord state when all positions report released, or timeout-based reset).
  3. Retrace bookkeeping: verify the translation stack + formatter snapshot restore can't erase more output than the popped entries produced.

Repro: stroke normal prose on the STEN layer; failure appears within a few sentences.

Observed on hardware (corne, v4 engine, both dicts): - Occasionally a stroke triggers what looks like an undo/delete out of nowhere and erases multiple previous words. - The next key press after such an event merges into a chord with something stale (combos with keys that are no longer held). Likely causes to investigate: 1. **Fingerprint false-accepts on longest-match window probes.** Every stroke probes multi-stroke windows (previous strokes + new). Windows that are not real entries still pass the 4-bit fingerprint + membership gate ~3-4% of the time → bogus multi-stroke "match" fires a retrace that erases the previous translations and emits an unrelated entry. With several probes per stroke this compounds to a per-stroke wrong-fire rate in the 10-20% range. - Planned mitigation (from the v4 design spec): resurrect the per-dict prefix Bloom filters (~24 KB, left half has budget) and gate multi-stroke window probes on "this stroke can start a multi-stroke entry". Kills ~95% of bogus probes. 2. **keys_held / chord state desync across halves.** If a release event is lost or reordered over BLE, `keys_held` never reaches zero, so the next press merges into the stale chord. Needs a defensive resync (e.g. clear chord state when all positions report released, or timeout-based reset). 3. Retrace bookkeeping: verify the translation stack + formatter snapshot restore can't erase more output than the popped entries produced. Repro: stroke normal prose on the STEN layer; failure appears within a few sentences.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: afiqzudinhadi/zmk-steno-engine#1
No description provided.