Skip to content

Auto Phone Mode On Launch

Plan Metadata

  • Plan type: plan
  • Parent plan: N/A
  • Depends on: N/A
  • Status: draft

Status semantics: - draft: Plan is being created or updated and is not final. - approved: Plan is approved but not yet applied in code. - documentation: Code currently exists and matches the plan contract.

Update rule: - When an existing plan is edited, set status to draft until re-approved.

System Intent

  • What is being built: On every app launch (after wearables initialize), detect whether the glasses are currently connected. If glasses are not connected, automatically override the saved recording device preference to "phone". If glasses are connected, honour the saved preference as-is.
  • Primary consumer(s): AppInit component (runs the initialization sequence); recording-device-preference module (owns the preference state).
  • Boundary (black-box scope only): WearablesModule.isAnyDeviceAvailable() is the glasses-connected signal — its internals are out of scope. AsyncStorage is the persistence layer — its internals are out of scope.

Stage Gate Tracker

  • [x] Stage 1 Mermaid approved
  • [x] Stage 2 Flows approved
  • [ ] Stage 3 Logs + Deployment approved or skipped

Mermaid Diagram

graph TD
  AppInit["AppInit\n(component)"]:::unchanged
  hydrateRecordingDevicePreference["hydrateRecordingDevicePreference()\nrecording-device-preference.ts"]:::changed
  AsyncStorage["AsyncStorage\n(persistence)"]:::unchanged
  WearablesModule["WearablesModule.isAnyDeviceAvailable()\n(native bridge)"]:::unchanged
  RecordingDeviceState["selectedRecordingDevice\n(in-memory store)"]:::unchanged

  AppInit -->|"calls on init"| hydrateRecordingDevicePreference
  hydrateRecordingDevicePreference -->|"read saved preference"| AsyncStorage
  AsyncStorage -->|"storedDevice or null"| hydrateRecordingDevicePreference
  hydrateRecordingDevicePreference -->|"check connection"| WearablesModule
  WearablesModule -->|"isConnected: bool"| hydrateRecordingDevicePreference
  hydrateRecordingDevicePreference -->|"set device (phone override if not connected)"| RecordingDeviceState

classDef unchanged fill:#d3d3d3,stroke:#666,stroke-width:1px;
classDef changed fill:#a8e6a3,stroke:#666,stroke-width:1px;

Flows

Global Types

RecordingDevice = "glasses" | "glasses-audio" | "phone"

StandardError {
  message: string (human-readable description of what went wrong)
}

Flow: hydrateRecordingDevicePreference

  • Core files: main/app/lib/recording-device-preference.ts
  • Test files: main/app/__tests__/recording-device-preference.test.ts (new file)

Types

HydrateInput {
  // no arguments — reads AsyncStorage and WearablesModule internally
}

HydrateOutput {
  // void — side-effects only: updates selectedRecordingDevice in-memory and emits to listeners
}

Paths

path input output path-type notes updated
hydrate.glasses-connected-saved-glasses stored = "glasses", isAnyDeviceAvailable = true selectedRecordingDevice = "glasses" happy path Glasses are connected; stored glasses preference is kept yes
hydrate.glasses-connected-saved-glasses-audio stored = "glasses-audio", isAnyDeviceAvailable = true selectedRecordingDevice = "glasses-audio" happy path Glasses are connected; stored glasses-audio preference is kept yes
hydrate.glasses-connected-saved-phone stored = "phone", isAnyDeviceAvailable = true selectedRecordingDevice = "phone" happy path User explicitly chose phone; kept even though glasses are connected yes
hydrate.glasses-not-connected-saved-glasses stored = "glasses", isAnyDeviceAvailable = false selectedRecordingDevice = "phone" happy path (new override) Glasses not connected; override saved glasses preference to phone yes
hydrate.glasses-not-connected-saved-glasses-audio stored = "glasses-audio", isAnyDeviceAvailable = false selectedRecordingDevice = "phone" happy path (new override) Glasses not connected; override saved glasses-audio preference to phone yes
hydrate.glasses-not-connected-saved-phone stored = "phone", isAnyDeviceAvailable = false selectedRecordingDevice = "phone" happy path Already phone; no change needed yes
hydrate.no-saved-preference-glasses-connected stored = null, isAnyDeviceAvailable = true selectedRecordingDevice = "glasses" (default) happy path No stored preference; default is glasses when connected yes
hydrate.no-saved-preference-glasses-not-connected stored = null, isAnyDeviceAvailable = false selectedRecordingDevice = "phone" happy path No stored preference; default is phone when not connected existing behavior, unchanged
hydrate.storage-read-error AsyncStorage throws, isAnyDeviceAvailable = false selectedRecordingDevice = "phone" (fallback) error Log error; fall through to connection-aware default unchanged
hydrate.storage-read-error-glasses-connected AsyncStorage throws, isAnyDeviceAvailable = true selectedRecordingDevice = "glasses" (fallback) error Log error; fall through to connection-aware default unchanged

Pseudocode

hydrateRecordingDevicePreference():
  storedDevice = await AsyncStorage.getItem(STORAGE_KEY)

  if isRecordingDevice(storedDevice):
    isConnected = isGlassesDeviceAvailable()

    // If stored preference is a glasses mode but glasses are not connected,
    // override to phone for this session. Do NOT persist the override —
    // the user's stored preference stays intact so the next launch with
    // glasses connected will restore the saved glasses mode.
    if (storedDevice === "glasses" || storedDevice === "glasses-audio") && !isConnected:
      setSelectedRecordingDeviceValue("phone")
      return

    setSelectedRecordingDeviceValue(storedDevice)
    return

  // No stored preference — fall through to connection-aware default
  fallbackDevice = getDefaultRecordingDevice()   // already calls isAnyDeviceAvailable()
  if selectedRecordingDevice !== fallbackDevice:
    selectedRecordingDevice = fallbackDevice
    emit()

Key design decision: the override is in-memory onlyAsyncStorage is NOT updated when we override to phone. This preserves the user's explicit glasses preference for the next launch when glasses may be connected.

Logs

Source Location
App (JS) Frontend logger — recording-device flow

New log steps to add in hydrateRecordingDevicePreference:

step when
recording_device_glasses_not_connected_override Glasses preference stored but glasses not available; override to phone. Log { storedDevice, override: "phone" }

Deployment

  • Mechanism: local only
  • Deploy command:
    cd main/app && npx expo start
    
  • Notes: JS-only change; no native rebuild required.

ONCE YOU GET APPROVAL FROM THE DEVELOPER, DELETE THIS LINE AND UPDATE THE STAGE GATE TRACKER

After all stages are approved, apply .agent/skills/reconcile-plans/SKILL.md to propagate contract updates across linked plans.