# Journey: Nyx sky event to Tara contemplative pause

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 overclaim** — `taraSessionState=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`](../../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

- [`customer/06-nyx/nyx-event-detail.md`](../customer/06-nyx/nyx-event-detail.md)
  — fixed event detail and Tara recommendation card.
- [`customer/03-tara/tara.md`](../customer/03-tara/tara.md) — hydrated Tara
  destination and timer player.
- [`customer/06-nyx/nyx.md`](../customer/06-nyx/nyx.md) — live ephemeris hub
  whose optional Tara cue is currently not populated.

## Cross-references

- [`nyx-event-calendar-sync-reminder.md`](./nyx-event-calendar-sync-reminder.md)
  — fixed rich event identity versus the dynamic ephemeris authority.
- [`nyx-tonight-observation.md`](./nyx-tonight-observation.md) — `/nyx` live
  mapper, emitted event ids, and observation boundaries.
- [`first-tara-sit.md`](./first-tara-sit.md) — Tara player, completion, and
  persistence boundaries outside this bridge.
- [`tara-to-nisaba-handoff.md`](./tara-to-nisaba-handoff.md) — another direct
  relationship-builder handoff with deeper destination proof.
- [`assistant-handoff-context-carry.md`](./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?
