Skip to content

Keyboard shortcuts, live tab title, bounded dependencies, and belt-sequence hardening (ROADMAP 2.6, 3.3, 3.13) - #24

Merged
SeanathanVT merged 8 commits into
developmentfrom
feature/desktop-quick-wins
Oct 9, 2026
Merged

SeanathanVT merged 8 commits into
developmentfrom
feature/desktop-quick-wins

Conversation

@SeanathanVT

Copy link
Copy Markdown
Owner

Summary

Desktop quick wins from the roadmap, plus fixes for race conditions that keyboard use made easier to hit, found in several rounds of review.

Features

  • Keyboard shortcuts (3.3): Space pause/resume, ↑/W and ↓/S speed, L/K/M presets, ? for a per-screen list. Start and End Session have no key, so a stray press can't start an unattended belt or end a walk. Toggle in Settings (keyboard_shortcuts_enabled, default on), as WCAG 2.1.4 requires.
    • Each shortcut clicks its button, so it goes through the same submit path, double-tap guard, and cross-site check.
    • Ignored while typing, with modifiers held, and while a dialog, the theme popover, or the phone menu is open. Space on a keyboard-focused button keeps its normal meaning, tracked by input type rather than :focus-visible so behavior matches across Safari, Chrome, and Firefox.
    • aria-keyshortcuts is the single source for the tooltips and the ? list. Shortcuts work without Bootstrap, and closing the ? list restores focus.
  • Live tab title (3.13): 3.2 mph · 1.40 mi - WalkingDad while walking.
  • Bounded dependencies (2.6): each direct dependency, including markupsafe, is pinned at its tested version and capped below the next major.

Fixes

  • A quick second press can't undo Start/Pause/Resume/End. Routes set belt_transitioning before scheduling, guarded by a generation counter so only the newest sequence clears it, and reset when a new BLE loop starts. Pages render with buttons disabled, re-enable them after 15 s if no stats update arrives, and reload on a back/forward-cache restore.
  • End stops the belt when it cancels an unfinished Pause.
  • Pause and End cancel a pending speed change before stop_belt. Speed changes are ignored while a belt sequence is in flight, and checked and queued under the session lock.
  • Speed rounding: round() instead of int(), which set e.g. 3.8 + 0.6 to 4.3.
  • Concurrency: sequences and speed changes register before cancelling their predecessor. _cancel_task lets the caller's own cancellation propagate, cancels tasks from another event loop on that loop, and logs errors raised during cancellation. _handle_disconnect survives tasks on a closed loop.
  • Shutdown overlay stops stats handling, including on the connecting page, and resets the tab title.

Docs

  • CHANGELOG [Unreleased], README (features, config table), and ROADMAP 2.6, 3.3, 3.13 and 3.18.
  • New ROADMAP items:
    • 1.7: Bleak 3's disconnect callback is never registered.
    • 1.8: on a C2, commands are ignored after a press on the physical remote, back-to-back speed commands are dropped, and the status packet's app_speed byte carries the target speed (km/h × 10).
    • 1.9: firmware version check and update replicating KS Fit (opt-in, fetched from KingSmith, nothing bundled), starting with an APK spike.
  • AGENTS.md: follow common UI conventions and WCAG 2.2 AA where practical.

Testing

  • 400 tests pass (with RuntimeWarnings treated as errors), and ruff is clean. Each new guard has a test that fails when the guard is removed.
  • Browser behavior was checked in a throwaway jsdom harness across the active, paused, start and connecting screens, including the no-Bootstrap case.
  • Manual check on macOS Safari with a C2: every shortcut, the focus behavior, the settings toggle, and the tab title.

Follow-ups

  • ROADMAP 1.7 and 1.8, each on its own bugfix/ branch.
  • Investigating KS Fit's firmware check and update (APK analysis started).

🤖 Generated with Claude Code

SeanathanVT and others added 8 commits October 8, 2026 14:38
…s (ROADMAP 2.6, 3.3, 3.13)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…screen shortcut help (ROADMAP 3.3)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…, 3.13, 3.18)

Shortcuts:
- Derive tooltips and the ? list in JS from aria-keyshortcuts; hotkey()
  now emits only that attribute
- Track keyboard vs mouse focus via capture-phase keydown/pointerdown
  instead of :focus-visible, so Space presses a keyboard-focused control
  but not one focused by a mouse click or script
- Restore focus when the ? list closes (WCAG 2.4.3); block keys while
  any modal is opening; only block for the phone menu while it's visible
- Create the help modal lazily so shortcuts survive a Bootstrap CDN failure

Belt sequences:
- Set belt_transitioning in the start/pause/resume/end routes, guarded by
  a generation counter so only the newest sequence can clear it; reset
  it when a new BLE loop starts
- Register sequences and speed changes before cancelling their
  predecessor, so they can't run concurrently or escape a disconnect
- _cancel_task: let the caller's own cancellation propagate, and cancel
  tasks from another event loop on that loop
- End Session stops the belt when it cancels an unfinished sequence
- Ignore speed changes while a belt sequence is in flight, checked and
  queued under the session lock
- Round, not truncate, km/h to device units (3.8 + 0.6 set 4.3)

Pages:
- Render buttons disabled while transitioning, re-enabling after 15 s if
  no stats update arrives; reload on back/forward-cache restore
- Single tab-title format, reset by the shutdown overlay, which also
  stops stats handling (connecting page included)

Docs: CHANGELOG, ROADMAP 2.6/3.3/3.13/3.18, new 1.8 (C2 behavior after
the physical remote, dropped back-to-back commands, app_speed target).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ROADMAP 3.3, 3.13)

- Pause and End sequences cancel a queued speed change before stop_belt,
  so a step can't reach a stopped belt; correct the misleading comment
- _handle_disconnect: suppress RuntimeError from task.cancel() on a
  closed loop, so a stale task can't abort reconnect scheduling
- _cancel_task: log an error a task raised while being cancelled
- Settings hint uses parentheses instead of " -- "
- Tab title only reassigned when it changes

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Opt-in check of the pad's firmware against KingSmith's latest, and
an over-the-air update replicating KS Fit, with no firmware bundled.
Starts with a spike decompiling KS Fit 6.6.0 to find the version
endpoint, image format, and update procedure; the update is built
only if that procedure proves safe. Also notes the C2's firmware
(6.1.2, software 6.3.0) in 1.8.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
On Python 3.10, asyncio.wait_for returns normally when a cancel lands
as the lock is handed over, so asserting the step was cancelled failed
there (3.12+ raises). Model the actual hazard instead: a step waiting
on its predecessor outside the lock while Pause/End takes it. Passes
on 3.10 and 3.12; fails on both without the cancel.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@SeanathanVT
SeanathanVT changed the base branch from main to development October 9, 2026 13:31
@SeanathanVT
SeanathanVT merged commit 560218c into development Oct 9, 2026
2 checks passed
@SeanathanVT
SeanathanVT deleted the feature/desktop-quick-wins branch October 9, 2026 13:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant