# Journey: First Tara sit

A freshly onboarded user's first contemplative session inside Tara: Home
continuity → BFF-backed Tara room → timer/ambient player → completion → local
reflection UI → cross-domain next steps. The current player has a real ambient
WAV, a real start/completion write seam, and accessible transcript/caption
controls. It does **not** yet play narration, persist a reflection entered after
completion, advance the room's course row, or prove an Arete streak update.
Those distinctions keep the first-sit experience useful without turning its
remaining product contract into shipped behavior.

## Personas

- **Onboarded customer, first sit** — primary; just finished `OnboardingWizard`,
  hasn't tapped a Tara card before
- **Returning customer with broken streak** — re-engages today; verifies humane
  recovery framing per Lilith tone policy
- **Reduced-motion user** — `prefers-reduced-motion: reduce`; verifies
  audio-first flow without auto-playing animations
- **Hearing-impaired user** — relies on transcripts and captions; verifies the
  alternative modality path

## Pre-conditions

- User signed in, onboarding complete (`OnboardingResumeBanner` is hidden on
  `/`)
- User declared an interest that maps to Tara during the Interests step of
  onboarding (so the Tara ritual continuation surfaces on `/`)
- Audio output is optional. The BFF-generated ambient track is the only audio
  wired by this player; a failed fetch leaves the sit silent and says so.
- This route does not request microphone permission or mount a separate Psyche
  voice-session envelope.
- Network healthy; no offline branch in this journey (covered separately in
  [`offline-first-time-use.md`](./offline-first-time-use.md))

## Steps

### 1. Land on Home, locate today's sit rail

- [x] User opens `/` after sign-in
- [x] `HomeWorkspace` renders; `HomeTaraRitualContinuationSection` is visible
      between the KPI grid and the daypart rail
- [ ] Section header "Tara" links to `/tara`
- [x] "Resume ritual" button is present when a prior session exists; first-time
      users see "Pick a practice" or similar entry copy instead (verify in
      `HomeTaraRitualContinuationSection`)
- [ ] Telemetry: page-load fires `home_dashboard_loaded` (or equivalent)
- [x] **Verify**:
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
      Tara ritual continuation section

### 2. Enter the Tara hub

- [x] Click the Tara section header link OR the Tara `DomainCardGrid` card
- [x] Navigation hits `/tara`; `page.tsx` runs `await getTara()` and renders
      `<TaraRoom data={data} />`
- [ ] Shell header stays mounted; Tara is highlighted in the domain switcher
- [x] `TaraRoom` lays out the eyebrow "Tara · sit", the manuscript display title
      ("Today's sit · 12 min"), the description, and the course continuation row
- [ ] Telemetry: route navigation fires `tara_hub_viewed` (or equivalent
      domain-entry event)
- [x] **Verify**: [`customer/03-tara/tara.md`](../customer/03-tara/tara.md)
      Today's sit card

### 3. Inspect the today's-sit card before pressing Begin

- [ ] Display title (`data.todaysSit.title`) renders in Cormorant Garamond at
      ~56px
- [ ] Italic body description from `data.todaysSit.description` is readable
- [x] Round play button with
      `aria-label="Begin sitting · ${data.todaysSit.title}"` sits next to the
      "Begin · 12 min" label
- [x] Below the play button:
      `data.todaysSit.teacher · narrated ·     data.todaysSit.pathLabel · session NN of M`
- [x] `LDots` progress glyphs show the user's position in the course
- [ ] Teacher byline is a link to the teacher profile under
      `/domains/tara/teachers/<id>`
- [ ] **Verify**: [`customer/03-tara/tara.md`](../customer/03-tara/tara.md)
      Today's sit card / Teacher byline

### 4. Press "Begin"

The Begin button is now wired. `rooms.tsx` renders the round play button (and
the "Begin · N min" label) as a Next.js `<Link>` to `/tara/sit/<id>`, where
`<id>` is the slug of the recommended sitting (e.g.
`/tara/sit/when-the-mind-wanders`). The sittings list rows are also linkable so
a user can resume any prior session.

- [x] Pointer click / Enter / Space activates the play link
- [x] Navigation lands on `/tara/sit/<id>` which renders `TaraSitPlayer`
- [x] V1 exposes the player session telemetry contract: the hub link carries
      `data-telemetry-event="tara_sit_started"` and
      `data-telemetry-surface="tara_hub"`, while the player transport fires
      `tara_sit_started` / `tara_sit_paused` / `tara_sit_resumed` on toggle. The
      broader Psyche session-envelope ownership remains architecture-level and
      is not separately surfaced in this route.
- [x] The BFF-generated ambient loop begins when ready; there is no guided
      narration audio. Visual transitions honor `prefers-reduced-motion: reduce`
      (player reads `matchMedia` and disables its transform animation when
      reduce is set)
- [x] Telemetry: `tara_sit_started`, surface=`tara_hub`
- [x] **Verify**: [`customer/03-tara/tara.md`](../customer/03-tara/tara.md)
      "Begin sit" interaction
- [ ] **Verify** [`V1/features.md#tara`](../../V1/features.md#tara) session
      state model

### 5. Mid-sit controls and accessibility

- [x] Play / pause / scrub controls expose ≥ 44×44 px touch targets on coarse
      pointers
- [x] The ambient-mix slider responds to keyboard and changes the real ambient
      element's volume with `aria-valuenow` exposed.
- [x] A 0.85×–1.25× “Voice speed” slider is keyboard-operable, but no narration
      element consumes its value yet; it is a UI-state control, not a
      quality-preserving resampler.
- [x] The transcript toggle exposes the sitting script (or a generic fallback).
      It is not time-coded to narration.
- [x] Captions toggle and large-text variant work; caption copy is selected from
      timer progress rather than an audio cue track.
- [ ] For hearing-impaired users, an alternative modality (vibration-based
      pacing where the device supports it) is reachable
- [ ] Pausing for longer than the per-modality `drift_idle_seconds` threshold
      transitions the session into `drifted` state without surfacing shame copy
- [x] **Verify**: [`shell/06-keyboard-a11y.md`](../shell/06-keyboard-a11y.md)
      Focus management / Motion and animation
- [ ] **Verify** [`V1/features.md#tara`](../../V1/features.md#tara) Tara Audio,
      Accessibility, and Save/Share

### 6. Completion

- [x] Session reaches end of audio; partial-completion threshold (≥ 80% of audio
      counts as complete per features.md) means even an early-exit user gets the
      completion path if they crossed the line
- [x] Completion attempts to write duration, completion state, origin, and the
      reflection value present at the moment of completion to the Tara BFF.
      Because reflection is normally entered afterward, that payload is `null`;
      mood-after is not included.
- [ ] Treat a non-2xx completion response as a failure and queue/retry it. The
      current effect queues only a thrown network error and does not inspect
      `response.ok`.
- [ ] Streak indicator on the next render of `/tara` or
      `HomeAretePracticeSection` increments where appropriate
- [x] Lilith tone copy on completion does not shame the user for skipping; copy
      reads "thank you" rather than "well done" per Lilith policy
- [ ] **Verify** [`V1/features.md#tara`](../../V1/features.md#tara) Completion
      events

### 7. Reflection capture

Tara's `journal capture` field on the completion event is the entry point for
reflection.

- [x] A reflection prompt surfaces after the audio ends (input or freeform text
      area)
- [x] User types a 1-3 sentence reflection
- [x] Submit keeps the reflection in component state and, while online, waits
      300 ms before rendering “Saved · attached to today.” No BFF request or
      durable browser write backs that online acknowledgement today.
- [x] If submission fails (network blip), the reflection is queued locally with
      a "saved locally, will sync" hint — no silent loss
- [ ] **Verify**:
      [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md)
      for the recipient of streak increments
- [ ] **Verify** [`V1/features.md#tara`](../../V1/features.md#tara) Cross-domain
      Tara companions

### 8. Cross-domain bridges fire

After completion, Tara may offer next-step bridges per features.md.

- [x] **Arete next step** — "Add this to your routine" or "View today's habit"
      CTA → `/arete` or a specific habit detail
- [x] **Nisaba passage companion** — "Read related passage" CTA → a Nisaba route
      (verify which Nisaba route ships in V1 as the passage detail)
- [x] **Nyx next step** — the current completion surface always renders the
      static Nyx CTA to `/nyx`; it is not profile/daypart-selected.
- [ ] **Veritas / Sophia explanatory note** — when a teacher cited a scientific
      claim, offers a grounded-evidence trail link
- [ ] **Verify**:
      [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md)
      Streak heatmap update
- [ ] **Verify**:
      [`customer/07-nisaba/nisaba.md`](../customer/07-nisaba/nisaba.md) passage
      entry
- [ ] **Verify**: [`customer/06-nyx/nyx.md`](../customer/06-nyx/nyx.md)
      perspective prompt

### 9. Return to Tara hub and observe continuation

- [ ] Navigate back to `/tara` (or accept the auto-return)
- [ ] `data.sittings` row corresponding to today's sit transitions to
      `state: 'done'` glyph (checkmark per `rooms.tsx`)
- [ ] The next sitting (`row.state === 'here'`) is now the next prerequisite
      session, matching `continuation_state.per-program` progress
- [ ] Streak panel updates if Tara surfaces a streak count
- [ ] **Verify**: [`customer/03-tara/tara.md`](../customer/03-tara/tara.md)
      Course continuation row / States

### 10. Return to Home and observe continuation rails

- [x] Go back to `/`
- [x] `HomeTaraRitualContinuationSection` now shows a "Resume ritual" affordance
      pointing to today's completed sit's reflection / replay (verify behavior)
- [ ] Activity feed (`ActivityFeed`) has a new entry for today's completion
- [ ] **Verify**:
      [`customer/02-home-discovery/activity.md`](../customer/02-home-discovery/activity.md)
      Continuity timeline
- [ ] **Verify**:
      [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
      Activity feed

## Post-conditions

- The player reaches `completed` or `partially-completed` and attempts one Tara
  completion write for the current browser session.
- Offline reflection submission either writes `tara:reflection:<id>` or
  truthfully says the draft is in this tab only. The online “Saved” branch does
  not yet prove a durable reflection entry.
- The completion view exposes Arete, Nisaba, and Nyx next-step links. Following
  a link does not prove a streak, journal, or course-row mutation.
- Verified telemetry hooks/attributes cover start, pause, resume, finish-early,
  reflection-save intent, and cross-domain link intent. There is no verified
  `tara_hub_viewed` emission in this route.

## Failure modes to verify

- [ ] **"Begin" still has no destination** — `rooms.tsx` should render the play
      button as a `<Link href="/tara/sit/${data.todaysSit.id}">`. If clicking it
      does nothing, the wiring regressed; reopen as P0 and verify the
      `TaraSitPlayer` route renders at `/tara/sit/<id>`.
- [ ] **Audio fails to load** — UI surfaces "couldn't load audio" with a retry
      CTA; pinned-audio fallback offered if the user previously opted in;
      session_state remains `not-started`
- [ ] **Mid-session network drop** — session_state continues locally; transcript
      sync queues; on reconnect, transcript catches up and completion event
      re-syncs
- [x] **User exits at < 80% completion** — session_state transitions to
      `partially-completed`; humane copy avoids shaming language; no streak
      penalty. Evidence: `first-tara-sit-deepening.spec.ts` finishes the route
      player immediately, asserts the partial-completion copy, and confirms the
      full-completion "A sit, kept." copy is absent.
- [x] **Reflection submission fails locally** — browser offline mode keeps the
      page loaded, `navigator.onLine=false`, Save reflection writes
      `tara:reflection:<id>` to localStorage, and the queued sync dot plus
      "Saved locally, will sync" hint stay visible. After reconnect, current V1
      behavior keeps the local queue intact and does not falsely flip the UI to
      "Saved · attached to today".
- [ ] **Reflection reconnect drain** — the claimed "sync resumes on reconnect"
      behavior is not wired for `tara:reflection:<id>` yet; the browser proof
      now documents the non-drain state until a BFF route + client drain exists.
- [ ] **Crisis-like reflection** — no Lilith preflight is wired to the
      reflection submit handler today. It must fail closed into the safety path
      before any future durable journal write (per
      [`V1/features.md#lilith-persona-policy`](../../V1/features.md#lilith-persona-policy));
      do not treat the current local “Saved” state as screened.
- [ ] **Streak-recovery state on returning user** — Arete streak shows "welcome
      back" framing rather than guilt-inducing UI ("two quiet days, folded in"
      per `/arete/streak` body copy)

## E2E coverage

- Backed by
  [`apps/oshun/web/e2e/tara-full-journey.spec.ts`](../../apps/oshun/web/e2e/tara-full-journey.spec.ts),
  [`apps/oshun/web/e2e/tara-session-player.spec.ts`](../../apps/oshun/web/e2e/tara-session-player.spec.ts),
  and
  [`apps/oshun/web/e2e/home-tara-centering-continuity.spec.ts`](../../apps/oshun/web/e2e/home-tara-centering-continuity.spec.ts)
  — these cover the Tara hub Begin-link, the immersive player (play/pause,
  scrub, transcript, speed-control state, real ambient audio, share), session
  completion, the local reflection UI, Nisaba/Metis/Arete/Nyx cross-domain
  handoffs, and home continuity rail visibility.
- Backed by
  [`apps/oshun/web/e2e/first-tara-sit-deepening.spec.ts`](../../apps/oshun/web/e2e/first-tara-sit-deepening.spec.ts)
  — drives the steps 1–2 first-time-vs-returning distinction on the Home rail
  (asserts `data-home-tara-state="fallback"` with a daypart primary-action when
  no continuity record exists, and `data-home-tara-state="live"` with a "Resume
  ritual" CTA when one does), the step-4 reduced-motion path (the player
  transport transition collapses to `none` under
  `prefers-reduced-motion: reduce`), and the step-5 mid-sit accessibility paths
  (play/pause/scrub transport, transcript, captions, large text, plus ArrowRight
  on the Voice playback-speed and Voice ambient-mix sliders each increments its
  `aria-valuenow`). The same spec now installs the browser clock before loading
  `/tara/sit/when-the-mind-wanders`, starts the real player, fast-forwards past
  `DRIFT_IDLE_SECONDS = 90`, asserts `data-session-state="drifted"` plus the
  soft pause copy, scrubs forward to recover to `paused`, and resumes with the
  `tara_sit_resumed` telemetry hook intact. It also drives the unknown sitting
  route state: `/tara/sit/not-a-real-sitting-id` renders the app-level 404 UI,
  does not mount the player, preserves usable 404 search, and browser-back
  returns to `/tara`. It also drives the reflection failure mode with real
  browser offline mode: after completion, `context.setOffline(true)` makes
  `navigator.onLine=false`, Save reflection queues `tara:reflection:<id>` in
  localStorage, renders `data-tara-reflection-sync-state="queued"` via
  `LSyncDot`, shows the "Saved locally, will sync" hint, returns the browser
  online, and asserts the queued UI plus localStorage draft remain because the
  route has no client-side drain yet.
- **Coverage depth**: deep — see [`coverage.md`](./coverage.md).
- **Uncovered**:
  - Step 5: vibration-based pacing is not implemented on the Tara player; the
    hearing-impaired path is covered through captions + transcript + large-text
    controls.
  - Step 8: automatic drain of queued reflection drafts on reconnect is not
    implemented; the current E2E records the non-drain behavior instead of
    claiming sync completion.
  - Step 8: Veritas/Sophia explanatory-note sequencing on completion is not
    asserted as a Tara completion CTA.
  - Step 9/10: persisted post-completion course-row advancement, ActivityFeed
    insertion, and Arete streak heatmap update remain partially covered through
    home continuity and cross-domain handoffs, not through a single end-to-end
    post-completion readback.

## Per-view files touched by this journey

- [`customer/02-home-discovery/home.md`](../customer/02-home-discovery/home.md)
  — entry rails and exit Activity feed
- [`customer/03-tara/tara.md`](../customer/03-tara/tara.md) — hub surface,
  Today's sit card, course continuation
- [`customer/04-arete/arete-streak.md`](../customer/04-arete/arete-streak.md) —
  streak heatmap update on completion
- [`customer/02-home-discovery/activity.md`](../customer/02-home-discovery/activity.md)
  — Activity entry for today's session
- [`customer/07-nisaba/nisaba.md`](../customer/07-nisaba/nisaba.md) — optional
  passage hand-off
- [`customer/06-nyx/nyx.md`](../customer/06-nyx/nyx.md) — optional perspective
  prompt

## Cross-references

- Feature spec: [`V1/features.md#tara`](../../V1/features.md#tara)
- Architecture: [`V1/ARCHITECTURE.md#tara`](../../V1/ARCHITECTURE.md#tara) and
  [`V1/ARCHITECTURE.md#psyche`](../../V1/ARCHITECTURE.md#psyche) for the session
  envelope
- Related journeys:
  - [`first-time-anonymous-visitor.md`](./first-time-anonymous-visitor.md) — the
    preceding journey
  - [`offline-first-time-use.md`](./offline-first-time-use.md) — what happens if
    network drops mid-sit
- Shell docs:
  - [`shell/06-keyboard-a11y.md`](../shell/06-keyboard-a11y.md) for audio /
    transcript a11y
  - [`shell/05-notifications.md`](../shell/05-notifications.md) for Tara ritual
    reminder push notifications
- Component sources:
  - `apps/oshun/web/src/app/tara/page.tsx`
  - `apps/oshun/web/src/components/lilith/rooms.tsx` (`TaraRoom`, line 61;
    today's sit play button `<Link>`, line 128, `aria-label` line 130)
  - `apps/oshun/web/src/lib/lilith-data/tara.ts` (`getTara` — fetches
    `/v1/tara/room` via `bffGet`; no fixtures)
  - `apps/oshun/web/src/components/home/HomeWorkspace.tsx`
  - `apps/oshun/web/src/components/home/HomeTaraRitualContinuationSection.tsx`
    (home ritual-continuation rail)

## Open questions / known gaps

- [x] `rooms.tsx` `TaraRoom` "Begin sitting" play button is now a Next.js
      `<Link>` to `/tara/sit/<id>`; the player route is implemented in
      `apps/oshun/web/src/app/tara/sit/[id]/page.tsx` +
      `apps/oshun/web/src/components/lilith/TaraSitPlayer.tsx`.
- [ ] Where reflection capture posts (Arete journal vs. Tara-internal log) —
      features.md mentions "export-to-journal-entry (with reflection capture)"
      but the V1 surface owning that endpoint isn't documented in tara.md
- [ ] Replace the online reflection `setTimeout` acknowledgement with an
      authenticated durable write and readback; drain queued offline drafts on
      reconnect.
- [ ] Wire the voice-speed control to a narration source or relabel it until
      narration exists.
- [ ] Treat non-2xx completion writes as failures and expose retry/sync state.
- [ ] Whether mid-sit voice responses are part of V1 or deferred — features.md
      mentions Psyche real-time voice runtime; the per-view file does not
      enumerate it
- [ ] Exact cross-domain bridge sequencing rules — are bridges offered in a
      fixed order, or do they pick the most-relevant one?
- [ ] Whether the partial-completion 80% threshold is fixed or configurable per
      modality
