V1 Web PWA · Journey

Journey: Nyx sky event to Tara contemplative pause

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

automated · 1 spec verdict: partial· 2026-05-29
9sections8 minread

On this page
Journey at a glance
ActorsSky watcherTara practitionerSafety and evidence reviewer
Automation1 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. Establish which Nyx surface owns the source"] s2["2. Inspect the deterministic relationship"] s3["3. Verify the card and identity boundary"] s4["4. Operate the Tara timer player"] s5["5. Inspect completion and local continuity"] s6["6. Follow the reciprocal Nyx suggestion"] s7["7. Interpret telemetry and the BFF endpoint c…"] s1 --> s2 --> s3 --> s4 --> s5 --> s6 --> s7 click s1 href "#1-establish-which-nyx-surface-owns-the-source" click s2 href "#2-inspect-the-deterministic-relationship" click s3 href "#3-verify-the-card-and-identity-boundary" click s4 href "#4-operate-the-tara-timer-player" click s5 href "#5-inspect-completion-and-local-continuity" click s6 href "#6-follow-the-reciprocal-nyx-suggestion" click s7 href "#7-interpret-telemetry-and-the-bff-endpoint-correctly" s7 --> v(["verdict: partial"]) click v href "../results/nyx-to-tara-bridge.html" style v stroke:#d6a531,color:#d6a531

This journey walks the implemented fixed-catalog bridge. It does not treat the dormant /nyx hub slot, the generic BFF recommendations endpoint, or browser- local theme continuity as if they were one system. A valid fixed Nyx event is classified by authored content metadata, linked to one Tara path, completed in the local timer player, and followed by a generic Nyx suggestion. No shared event/session envelope spans those screens.

Personas#

  • Sky watcher — opens a specific fixed Nyx event and wants a short, comprehensible contemplative next step.
  • Tara practitioner — follows the card, operates the timer player, and may use the reciprocal Nyx suggestion after completion.
  • Safety and evidence reviewer — must distinguish a curated content relationship from member personalization, crisis policy, emitted analytics, real audio delivery, and durable completion.

Pre-conditions#

  • Use a fixed event known to NYX_WEB_EVENT_RECORDS, such as /events/march-equinox. The live /nyx ephemeris mapper is a different authority and currently supplies no taraGroundingCue.
  • Use an authenticated customer shell where required for the destination. Do not infer member-aware ranking from authentication: the relationship builder receives no subject id or profile.
  • Expect every valid fixed event to receive one static Tara relationship. The builder has a default; it does not expose a no-match/abstain state.
  • Treat the Tara experience as timer-capable. Its hidden audio source uses an unproxied /api/v1 path and cannot consume the BFF's JSON audio-metadata envelope, so successful bridge automation does not prove media bytes.

Steps#

1. Establish which Nyx surface owns the source#

Open /events/march-equinox or the equivalent hydrated domain path. Verify the fixed event detail, not only /nyx. NyxRoom can render Ground with Tara when taraGroundingCue exists, but neither the live ephemeris mapper nor the unavailable mapper supplies it. The current hub therefore omits that link.

The fixed detail record is bundled in apps/oshun/web/src/components/domains/nyx/nyxEventPageModels.ts. It is not the same record returned by /v1/nyx/tonight, and its card does not call /v1/cross-domain/recommendations.

2. Inspect the deterministic relationship#

buildNyxTaraRecommendations passes fixed content fields to resolveNyxTaraPerspectiveRelationship. Event type plus the authored highlightFrame and content audience select a descriptor from the static Nyx → Tara relationship catalogue. Title and object names are passed but do not affect the decision.

For march-equinox, expect:

  • relationship seasonal_alignment_to_morning_opening;
  • reason perspective_handoff / Perspective continuity;
  • practice tara-morning-opening;
  • path /meditate/ritual/tara-morning-opening; and
  • seasonal-opening copy from the static descriptor.

Do not look for member preference, lineage, crisis state, history, time, location, or an API score. None enters this resolver. Every valid fixed event receives one relationship, including the fallback path.

3. Verify the card and identity boundary#

TaraRecommendationCard exposes the source event id, practice id, relationship kind, and proposed telemetry event as DOM attributes. Its real href contains the Tara practice path plus broad shell navigation context:

/domains/tara?origin=explore&stack=nyx&path=%2Fmeditate%2Fritual%2Ftara-morning-opening

The href does not contain eventId=march-equinox or a handoff id. Capture both facts: the source element knows the event, but the navigated Tara route does not.

4. Operate the Tara timer player#

Activate the link. TaraSurface parses the hydrated path and creates a generic Guided ritual session whose id is the final path segment. The Play control uses stack.at(-1) === 'nyx' to label itself with data-telemetry-surface="nyx_event_handoff"; that label is navigation-derived, not a validation of the source event.

Play, pause, seek, and reach completion. The player timer is real client state. The hidden audio element points at /api/v1/sessions/<id>/audio, while the Next proxy only maps /v1/*; the BFF endpoint also returns metadata with a nested track URL rather than audio bytes. Expect timer fallback unless that contract is redesigned.

5. Inspect completion and local continuity#

Completion sets the local screen, adds taraSessionState=complete to the current browser URL, and writes oshun.tara.theme-continuity.v1. The snapshot contains the generic Tara session and taxonomy and expires on read after 12 hours. Normal auth cleanup does not remove this browser-global key.

No handler posts a Tara completion, Nyx observation, Iris memory, originating event, or shared trace. A URL with taraSessionState=complete can reopen the completion screen without replaying the timer, so it is restoration state—not a completion receipt.

6. Follow the reciprocal Nyx suggestion#

The completion surface builds a new Tara → Nyx relationship from the generic Tara session. The March equinox path becomes a broad Nyx target such as /nightly-highlights with a ref and stack=tara. The original march-equinox id is unavailable to this builder, so the card cannot return to the exact event detail.

7. Interpret telemetry and the BFF endpoint correctly#

The event anchor and Tara Play control carry descriptive data-telemetry-event attributes. Their local handlers navigate or update player state. There is no delegated DOM telemetry listener and no direct analytics call from either control, so assert the attributes as a proposed contract—not delivered analytics.

/v1/cross-domain/recommendations is also separate. It is authenticated, member-ranked, cached, attributed, and instrumented server-side, but its target domain is limited to Nisaba or Metis. Its Nyx builders never return Tara and the event card does not consume it.

Post-conditions#

  • One fixed Nyx event maps deterministically to one Tara practice descriptor.
  • A real anchor reaches the requested Tara timer player and preserves broad origin/stack navigation context.
  • Source-event DOM metadata is distinguished from the href that drops it.
  • Timer completion, URL restoration, and the 12-hour theme snapshot are identified as browser-local state.
  • The reciprocal suggestion is identified as a new generic relationship, not an exact event return.
  • No hub CTA, personalization, crisis/lineage gate, audio bytes, emitted analytics, durable completion, Iris memory, or BFF Nyx → Tara item is claimed.

Failure modes#

  • Dormant hub assumption — conditional Ground with Tara JSX is mistaken for a link supplied by the live /nyx data mapper.
  • Unknown fixed event — the detail model returns the honest missing-event state. This is different from a valid event lacking a relationship; valid records always get one.
  • Personalization overclaim — authored content audience is read as the authenticated member's audience or preference segment.
  • Identity loss — source event attributes are assumed to cross the anchor even though the href carries only origin, stack, and practice path.
  • Audio contract mismatch — a JSON metadata endpoint or failed /api/v1 source is treated as played audio because the timer continued.
  • Completion overclaimtaraSessionState=complete or a local taxonomy snapshot is treated as a durable owner-scoped session receipt.
  • Return-path overclaim — the generic /nightly-highlights suggestion is described as returning to the originating event.
  • Telemetry overclaim — DOM attributes are mistaken for an emitted and acknowledged analytics record.
  • API overclaim — a 200 from the generic recommendation endpoint is treated as Nyx → Tara proof even though its targets are only Nisaba and Metis.
  • Shared-browser leak — a second account reads recent Tara theme continuity left by the first account within the 12-hour window.

E2E coverage#

  • apps/oshun/web/e2e/nyx-event-pages.spec.ts contains 15 cases. opens Tara perspective recommendations from selected Nyx content crosses March equinox → Tara timer → completion → generic Nyx suggestion; renders event-specific Tara recommendation semantics across Nyx event types checks five relationship buckets.
  • The bridge case asserts the DOM telemetry contract, not an analytics sink. It accelerates the timer by repeatedly dispatching the 15-second seek control and does not inspect audio bytes or a service receipt.
  • Focused domain/component/API suites cover the static resolver, every fixed event's one-recommendation rule, card href/attributes, Tara player state and local persistence, reciprocal route builder, and the BFF's non-Tara target boundary.
  • Coverage remains partial for a governed cross-domain handoff because member policy, event identity, media delivery, emitted telemetry, durable completion, account isolation, and exact return are not joined.

Per-view files touched#

Cross-references#

  • nyx-event-calendar-sync-reminder.md — fixed rich event identity versus the dynamic ephemeris authority.
  • nyx-tonight-observation.md/nyx live mapper, emitted event ids, and observation boundaries.
  • first-tara-sit.md — Tara player, completion, and persistence boundaries outside this bridge.
  • tara-to-nisaba-handoff.md — another direct relationship-builder handoff with deeper destination proof.
  • assistant-handoff-context-carry.md — an explicit persisted continuity contract for comparison.
  • Code: libs/oshun/domain-nyx/src/tara-relationship.ts, apps/oshun/web/src/components/domains/nyx/nyxEventPageModels.ts, apps/oshun/web/src/components/domains/nyx/NyxEventDetailWorkspace.tsx, apps/oshun/web/src/components/domains/TaraSurface.tsx, apps/oshun/web/src/components/domains/tara/SessionPlayer.tsx, and apps/oshun/web/src/components/domains/tara/taraSessionNyxSuggestions.ts.

Open questions#

  • Should the live /nyx mapper populate the dormant Tara cue, or should that UI branch be removed until it has a real content and policy owner?
  • Should a versioned, owner-scoped handoff carry the exact fixed event id, relationship, return URL, and issued-at time into Tara?
  • Which service should evaluate member preference, tradition/lineage, accessibility, and crisis policy, including an explicit abstention state?
  • Should the player fetch audio metadata from the proxied /v1 route and then load the authorized track URL, with browser tests proving bytes and fallback?
  • What durable mutation should prove elapsed completion and bind it to the source event without trusting a query flag?
  • Should recent theme continuity be member partitioned and removed on logout?
  • Will the DOM telemetry proposal gain a real emitter and sink receipt?
  • Should the reciprocal card return to the exact event before offering broader Nyx perspective content?
  • If the generic recommendation endpoint gains Tara targets, should this card consume that governed result instead of bypassing it with a static resolver?