Skip to content

feat(tracking): decode and persist current device tracking interval from mc=11 events #201

@brockamer

Description

@brockamer

During #197's investigation, we discovered the Mini 3 Plus emits messageCode=11 ("Track Interval") events when its active tracking interval changes — and the new interval value is conveyed in status.intervalChange (seconds) on the event payload. Per Garmin IPC Outbound spec §Message Codes Table.

We currently silent-drop mc=11 events via the standard non-Free-Text path (src/app.ts:225 area, non_free_text log line). With LOG_TRACK_PAYLOADS=true shipped in #199/#200 we now persist the full payload to logs, but we don't programmatically know the device's currently-active tracking interval at the moment of handleStopTrack.

Knowing it would let us:

  • Tag the refusal SMS for track_too_brief and track_no_pings with a hint: "device interval is 4hr — set it shorter in Garmin Explore" (high-signal operator advice that doesn't fit in 160 chars right now).
  • Expose the active interval in published track post frontmatter for diagnostics.
  • Correlate session-publish failures across time with device autonomous-interval-flap behavior — feeds into investigate: live-prod findings contradict spec §0 (mc=0 events + Satellite transport) #194's investigation.

Current state

  • mc=11 events arrive at /garmin/ipc and are silent-dropped (logged as non_free_text with full payload when LOG_TRACK_PAYLOADS=true, which is now the default).
  • The status.intervalChange field (seconds; 0 = unchanged) is in the payload but not extracted programmatically.
  • Per Garmin spec, intervalChange ALSO appears on mc=0/10/12 events — we could read it on any event, not just mc=11.

Acceptance criteria

Expand
  • A new KV key (e.g. track_interval:<imei>) tracks the device's last-known tracking interval in seconds, updated on any incoming event whose status.intervalChange > 0.
  • TTL ~24h (matches existing track_start TTL semantics).
  • handleStopTrack reads this key and includes it in the refusal SMS for track_too_brief / track_no_pings branches (within the 160-char budget — likely needs wording iteration).
  • Optional: include the value in published track post frontmatter (device_interval_seconds).
  • Regression tests for the KV write path and the refusal-SMS variant.
  • Real-device verification: change interval mid-session via the device UI, confirm the KV value updates.

Depends on

Related

Model & execution guidance

Cheap-tier work (USE a Haiku subagent):
  - Confirm the intervalChange field's range across recent production
    logs (now that LOG_TRACK_PAYLOADS=true is the default)
  - Scan Garmin IPC Outbound spec for any edge cases (negative values?
    reset semantics?) we haven't accounted for

Standard-tier work (USE a Sonnet subagent):
  - Add KV write path in the non_free_text inbound handler (one new
    helper in src/core/tracking.ts that updates track_interval:<imei>
    on any event with status.intervalChange > 0)
  - Read the key in handleStopTrack; thread into refusal SMS variants
  - Update tests/tracking.test.ts and tests/app.test.ts coverage
  - Update CLAUDE.md / PRD if device interval behavior becomes
    user-visible (publishable frontmatter, etc.)

Smart-tier moments (USE `advisor()`):
  - 160-char budget for refusal SMS gets tight when you add the
    interval hint — likely needs a phrasing-vs-truncation deliberation
  - Should the refusal SMS recommend specific interval values (e.g.
    "interval is 14400s; try 120s")? Or just nudge to "check device
    interval setting"? UX trade-off worth a second opinion

Subagent dispatches (USE these for the noted task):
  - Sonnet for the KV plumbing + handleStopTrack thread-through (~80
    line diff)
  - Haiku for the log-scan confirmation

Execution sketch:
  1. Spec the KV shape (one int + one timestamp? just the int?)
  2. Add the write path in the inbound handler
  3. Read in handleStopTrack; iterate on SMS wording
  4. Tests
  5. Real-device verification with explicit interval changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    Status
    In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions