V1 Web PWA · Journey

Journey: First Tara sit

A source-reconciled journey record for V1 Web PWA — shipped behavior, state boundaries, failure modes, and the automation evidence available today.

automated · 4 specs verdict: partial· 2026-05-29
9sections13 minread

On this page
Journey at a glance
ActorsOnboarded customer, first sitReturning customer with broken streakReduced-motion userHearing-impaired user
Automation4 E2E spec(s) · verdict: partial· 2026-05-29

Journey flow#

Generated from the authored steps below — click a node to jump to that section.

flowchart TD s1["1. Land on Home, locate today's sit rail"] s2["2. Enter the Tara hub"] s3["3. Inspect the today's-sit card before pressi…"] s4["4. Press Begin"] s5["5. Mid-sit controls and accessibility"] s6["6. Completion"] s7["7. Reflection capture"] s8["8. Cross-domain bridges fire"] s9["9. Return to Tara hub and observe continuation"] s10["10. Return to Home and observe continuation r…"] s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 --> s8 --> s9 --> s10 click s1 href "#1-land-on-home-locate-todays-sit-rail" click s2 href "#2-enter-the-tara-hub" click s3 href "#3-inspect-the-todays-sit-card-before-pressing-begin" click s4 href "#4-press-begin" click s5 href "#5-mid-sit-controls-and-accessibility" click s6 href "#6-completion" click s7 href "#7-reflection-capture" click s8 href "#8-cross-domain-bridges-fire" click s9 href "#9-return-to-tara-hub-and-observe-continuation" click s10 href "#10-return-to-home-and-observe-continuation-rails" s10 --> v(["verdict: partial"]) click v href "../results/first-tara-sit.html" style v stroke:#d6a531,color:#d6a531

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 userprefers-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)

Steps#

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

  • User opens / after sign-in
  • HomeWorkspace renders; HomeTaraRitualContinuationSection is visible between the KPI grid and the daypart rail
  • Section header "Tara" links to /tara
  • "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)
  • Verify: customer/02-home-discovery/home.md Tara ritual continuation section

2. Enter the Tara hub#

  • Click the Tara section header link OR the Tara DomainCardGrid card
  • Navigation hits /tara; page.tsx runs await getTara() and renders <TaraRoom data={data} />
  • Shell header stays mounted; Tara is highlighted in the domain switcher
  • 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)
  • Verify: 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
  • Round play button with aria-label="Begin sitting · ${data.todaysSit.title}" sits next to the "Begin · 12 min" label
  • Below the play button: data.todaysSit.teacher · narrated · data.todaysSit.pathLabel · session NN of M
  • 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 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.

  • Pointer click / Enter / Space activates the play link
  • Navigation lands on /tara/sit/<id> which renders TaraSitPlayer
  • 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.
  • 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)
  • Telemetry: tara_sit_started, surface=tara_hub
  • Verify: customer/03-tara/tara.md "Begin sit" interaction
  • Verify V1/features.md#tara session state model

5. Mid-sit controls and accessibility#

  • Play / pause / scrub controls expose ≥ 44×44 px touch targets on coarse pointers
  • The ambient-mix slider responds to keyboard and changes the real ambient element's volume with aria-valuenow exposed.
  • 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.
  • The transcript toggle exposes the sitting script (or a generic fallback). It is not time-coded to narration.
  • 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
  • Verify: shell/06-keyboard-a11y.md Focus management / Motion and animation
  • Verify V1/features.md#tara Tara Audio, Accessibility, and Save/Share

6. Completion#

  • 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
  • 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
  • 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 Completion events

7. Reflection capture#

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

  • A reflection prompt surfaces after the audio ends (input or freeform text area)
  • User types a 1-3 sentence reflection
  • 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.
  • 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 for the recipient of streak increments
  • Verify V1/features.md#tara Cross-domain Tara companions

8. Cross-domain bridges fire#

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

  • Arete next step — "Add this to your routine" or "View today's habit" CTA → /arete or a specific habit detail
  • Nisaba passage companion — "Read related passage" CTA → a Nisaba route (verify which Nisaba route ships in V1 as the passage detail)
  • 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 Streak heatmap update
  • Verify: customer/07-nisaba/nisaba.md passage entry
  • Verify: 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 Course continuation row / States

10. Return to Home and observe continuation rails#

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 destinationrooms.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
  • 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.
  • 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); 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-session-player.spec.ts, and 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 — 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.
  • 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#

Cross-references#

Open questions / known gaps#

  • 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