Repository navigation
fix: verify flash writes, gate setup on firmware, sticky guidance cards - #36
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root-caused a new ting whose buttons never worked over the 3.5mm audio path while dictation did (acoustic capture + offline decode of the recording, 2026-08-05): firmware below 1.0.8 plays the current slot sample on squeeze and button presses -- and the slots hold our chirp symbols -- so the stock engine injects extra symbols into the middle of every event word. Beacons survived on FEC; every button word died. Serial was unaffected, which is why USB looked fine. - Firmware is part of setup: Flash EP on a ting tingle has not seen at 1.0.8 routes into the guided upgrade flow, which reinstalls the payload at the end. Firmware bookkeeping is now PER DEVICE SERIAL -- a global flag had marked this brand-new unit as already upgraded because a different ting was. - Every Flash EP write is read back and checksummed before the eject, and the volume is synced; a truncated or reverted flash now fails loudly instead of reporting success and leaving a dead device. - Flash EP also ships a dry-bus config.json (SAMPLE-only presets). - Guidance cards stick: NSPanel hid itself on app deactivate, so the firmware ritual card vanished the moment focus moved -- leaving the user squeezing the handle with no instructions. Plus a one-flow-at-a- time guard (a re-click raced two flows into dueling failed/succeeded popups) and copy that says the button needs a true rapid double-click. - Test tooling: --decode-wav runs the production decoder over a line-in recording, --dump-flash-bytes emits the exact bytes Flash EP ships (both were decisive in this diagnosis). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
A newly flashed ting: dictation worked over 3.5mm, green/orange never did. Over USB everything worked.
Diagnosed by recording the raw line-in with ffmpeg and running the production decoder offline over the capture (new
--decode-wavflag), with serial events as ground truth. A 5ms frequency-ridge analysis showed the device acoustically playing more symbols than the payload ever queues — a "beacon" with five S0 chirps, a phantommodeChanged(4)that was really(2,3,1,3)on the wire.Root cause: firmware below 1.0.8 plays the current slot sample on squeeze and on button presses (the ting is an instrument, and our payload chains the stock callback for its bookkeeping). The slots hold chirp symbols, so stock playback sprays extra symbols into the middle of every queued event word. Beacons are 4 identical symbols and survive on FEC; diverse event words die. Serial is unaffected — hence USB looking healthy. Confirmed by A/B: after the firmware upgrade, all three event types decode.
Fixes
Firmware is part of setup. Flash EP on a ting tingle hasn't seen at 1.0.8 routes into the guided upgrade flow (which reinstalls the payload at the end). Firmware state is tracked per device serial — the global flag had marked this brand-new unit "already 1.0.8" because a different ting had been upgraded, which is exactly why the trap was invisible.
Verified flashing. Every write is read back and checksummed before the eject, plus a sync. A truncated/failed/reverted flash now fails loudly ("Flash verification failed — …") instead of reporting success and leaving a dead device. This also would have caught the earlier incident in this same session, where a stale 4096-byte payload sat on the device while Flash EP claimed success.
Dry-bus config.json now ships with every flash (SAMPLE-only presets).
Guidance UX.
NSPanelhides itself on app deactivate, so the firmware ritual card disappeared the instant focus moved — user left squeezing the handle with no instructions. Cards are now.statusBarlevel,hidesOnDeactivate = false, all-Spaces. Added a one-flow-at-a-time guard (a re-click raced two flows into simultaneous "failed" and "succeeded" popups) and fixed the copy: the button needs a true rapid double-click, not two deliberate presses.Testing
FlasherTests: verification mismatch cases incl. the exact truncation signature, dry-preset invariants, per-serial firmware bookkeeping) + payload tests green.Deferred
Payload inter-word pacing — rapid back-to-back presses still clip chirp edges at word boundaries even on 1.0.8 (isolated presses are clean). Real, but wants its own PR tested on both devices.
🤖 Generated with Claude Code