## Finger counting fix
Two writers were racing on CurrentStateStore.fingerCounts:
- FingerCounter.analyze writes by actual chirality (left/right/unknown)
from VNHumanHandPoseObservation.chirality
- The CurrentStateStore event-bus subscriber ALSO wrote, but always to
the key "unknown" regardless of which hand actually fired the event
Result: any frame with a hand showed both the correct "Left: 3 fingers"
row AND a duplicate "Unknown: 3 fingers" row in the Status panel.
Plus stale entries: a hand leaving the frame didn't clean up. The Left
entry stuck around forever.
Fix:
- CurrentStateStore is no longer a writer for finger counts from the
bus path (the subscriber comment now flags FingerCounter as the
authoritative writer).
- FingerCounter.analyze gets two new behaviors:
- When hands.isEmpty → CurrentStateStore.clearFingers() wipes all
stale per-chirality entries.
- When at least one hand is detected → it records every observed
chirality this cycle, then calls ageFingerEntries(currentSeen:at:)
to drop chirality entries that weren't seen this frame and are
older than the 1.2-second staleness window.
## Menu reorganization
Followed Mac UI conventions instead of the previous "App menu = dumping
ground" layout.
Before (everything in 3 menus):
- App: Settings, Log Stream, Status, Save Snapshot, Start Recording, Quit
- Faces: Enroll, Forget, Detection History
- Camera: Devices ▶, Refresh, Privacy Mode
After (5 menus by concern):
- VisionPOC: Settings (⌘,), Hide/Hide Others/Show All, Quit (⌘Q)
- File: Save Snapshot (⌘S), Start/Stop Recording (⇧⌘R)
- View: Status Panel (⌘I), Detection History (⇧⌘H), Log Stream (⌘L)
- Camera: <devices flat list>, Refresh List, Privacy Mode (⇧⌘P)
- Faces: Enroll Face (⌘E), Forget Face (⇧⌘E)
Notes:
- Camera devices are now a flat list at the Camera menu's root (no
nested submenu) for easier access. The menu uses NSMenuDelegate to
rebuild itself when opened, so devices are always fresh.
- Detection History keybinding moved from ⌘H to ⇧⌘H because ⌘H is the
standard macOS "Hide application" shortcut.
- A small `menuItem(_:action:key:mods:target:)` helper drains the
installMainMenu function from boilerplate so the 5 menus fit on one
screen of code.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>