[feature] Deliver Pebble watch consultation #7
- @github-anthodev opened this issue · Aug 29, 2026edited
🔢 Impact Version (SemVer)
MINOR
🌿 Suggested Branch
feature/watch-consultation/watch/7
📝 Description
Deliver the primary interaction: browse favorites and consult departures with an event-only request policy. Implement the five watch states, app-open/settled-selection/manual-refresh triggers, phone-cache-first rendering, atomic results, bilingual copy, compact AppMessage use, and battery-conscious platform rendering.
✅ Expected Behavior
Opening the watch app displays the last complete active-favorite result immediately when available, then allows one cache-governed refresh. Up/Down changes favorites and only the final selection after 500 ms can request; Select is the explicit refresh gesture. No timer/background path performs network I/O, and fresh 60-second phone cache suppresses upstream work.
📋 Acceptance Criteria
- Implement exactly
UNCONFIGURED,LOADING,READY,STALE,UNAVAILABLE; missing key/no favorites maps toUNCONFIGUREDwith a direct bilingual instruction to open companion options and configure a key/favorite; invalid/revoked key maps to actionableUNAVAILABLE. - On app open with
keyStatus=CONFIGURED, request the active favorite only after showing cached data; serve without backend/PRIM activity when cache age is under 60 seconds.MISSING/INVALIDmakes zero XHR. - Up/Down browse stored order immediately, but debounce the network trigger until selection is unchanged for 500 ms; intermediate scroll positions make zero XHR.
- Select explicitly refreshes only the active favorite. Fresh cache may answer it; suppress duplicate in-flight requests and never immediately retry a failure.
- Back keeps normal platform behavior. App close cancels pending debounce/ticks and, because PebbleKit JS stops, leaves no background work.
- Render the per-platform departure limit — three rows on emery, two rows on gabbro — with
screen.round-aware responsive layout,nextIntervalMinutes, delayed/cancelled state, source freshness, and refresh time from the foundation contract. - Keep the prior complete result visible during refresh; apply only one complete matching replacement. Do not resend AppMessage when normalized visible content and freshness are unchanged.
- Use minute ticks only while the app is active and only to update age/countdown; ticks must never trigger XHR/AppMessage. Use no second ticks, steady-state animations, vibration, or forced backlight.
- Build the UI in Piu with built-in system fonts only:
touchCount0 (button-only input), no font/media assets, no animations, and no touch polling. - Localize authored copy in French/English (
fr→ French, otherwise English); keep user/backend labels verbatim. - Both emulators (emery and gabbro) render all states and representative long French/English copy without clipping critical information, honoring
screen.roundon the round display. - Across a scripted 50-refresh/rapid-navigation run, remain within foundation heap/message budgets with zero dropped/failed AppMessages and no growth after steady state.
- A live result atomically replaces a recorded result; install/configure/consult one favorite on the named Pebble Time 2 (emery) physical watch.
- Record state/locale captures on emery and gabbro, per-event XHR/AppMessage counts, cache-hit and debounce proof, 50-refresh XS/heap/message evidence, live replacement, and Pebble Time 2 physical proof in a resolution comment.
🔗 Affected Endpoints/Routes
- No backend route is added.
- Consume the departure result/error route from
[feature] Normalize live PRIM departures(https://github.com/Anthodev/lapin-fute/issues/4) through PebbleKit JS and the AppMessage protocol from[feature] Establish the application foundation and contracts(https://github.com/Anthodev/lapin-fute/issues/2).
🧪 Tests to Add
Type Coverage Alloy model/protocol/Piu tests Five states, key-status mapping, navigation/debounce, cache-first/loading transitions, duplicate suppression, minute-tick no-I/O, atomic display PebbleKit JS integration tests App-open/settled-selection/Select triggers only, 60-second cache, no immediate retry, unchanged-result AppMessage suppression Localization/emulator tests Complete French/English resources, fallback/verbatim labels, every state and long label on both emery and gabbro (round layout included) Runtime smoke 50 refreshes with XS/heap/message counters; app close zero activity; stored config → live result; Pebble Time 2 physical watch
⚙️ Constraints
- The watch never searches, types, contacts external APIs, receives/stores the key, or owns a scheduler.
- The five states are exhaustive; a late/mismatched result never renders.
- App open, final favorite selection after 500 ms, and Select are the only request triggers; every trigger is cache-governed and app exit cancels outstanding UI scheduling.
- Fit the frozen platform/Alloy-runtime budgets (binary, loaded image/RAM, XS arenas, AppMessage) rather than dropping a target or enlarging AppMessage buffers speculatively.
- No background execution of any kind — periodic/background polling, Wakeup, Worker, timeline subscriptions — and no animations, vibration, touch input/polling, or backlight changes remain in scope; the Alloy app declares no background capability.
🔀 Dependencies
- Blocked by
[feature] Normalize live PRIM departures(https://github.com/Anthodev/lapin-fute/issues/4). - Blocked by
[feature] Persist and synchronize favorites(https://github.com/Anthodev/lapin-fute/issues/6). - Reuse the platform matrix, physical watch, shared contracts, localization resources, and AppMessage protocol from
[feature] Establish the application foundation and contracts(https://github.com/Anthodev/lapin-fute/issues/2).
⚠️ Impact on Existing Behavior
Replaces the recorded fixture display from
[feature] Establish the application foundation and contracts(https://github.com/Anthodev/lapin-fute/issues/2) with the complete consultation runtime and makes the configuration committed by[feature] Persist and synchronize favorites(https://github.com/Anthodev/lapin-fute/issues/6) user-visible.
🔍 Technical Context
Default layout intent:
Do not hard-code this English wording; use the frozen bilingual resource strategy and adapt layout to emery (three rows) and gabbro (two rows), honoring
screen.round.Required references
- Implement exactly
Sign in to comment.