# Journey: Nyx tonight observation

Nyx has a live, location-aware tonight card and a real owner-scoped observation
API, but the normal compact-room link between them is currently broken. The BFF
tonight card emits ephemeris ids such as `sunset`, `moonrise`, `moonset`, and
`sunrise`; the event-detail resolver only knows ids in the bundled web event
catalogue. Clicking a normal `/nyx` row therefore reaches **Event not found**.
The shipped successful route is `/domains/nyx/events` → catalog event detail →
observation. This page records both the useful route and the broken primary
route rather than allowing mocked E2E data to conceal the mismatch.

## Personas

- **Tonight visitor** — checks live rise/set conditions in the compact Nyx room.
- **Event browser** — chooses a known item from the domain event catalogue.
- **Observer** — records a note, visibility assessment, and event association.
- **Returning member** — expects their latest observation to appear in Nyx and
  home projections.

## Pre-conditions

- Use an authenticated session for owner-scoped observation read-back.
- Allow the BFF to resolve ephemeris/location input for `/v1/nyx/tonight`.
- For a successful detail path, start at `/domains/nyx/events`; do not replace
  its catalogue id with `sunset`, `moonrise`, `moonset`, or `sunrise`.
- Treat the compact sky diagram as illustrative. Its constellation-like line art
  and planet marker are not fully computed from the ephemeris payload.

## Steps

### 1. Inspect the live tonight card

Visit `/nyx`. `getNyx()` requests `/v1/nyx/tonight`, and the BFF builds rows
from current ephemeris data. An unavailable request produces an honest
unavailable model. The moon and rise/set facts are useful live information; the
decorative sky geometry and **Auto-orient** / compass chips are not an
interactive sensor view.

### 2. Record the compact-room identifier defect

Each `NyxRoom` row links to `/domains/nyx/events/${row.id}`. The emitted ids are
not present in `NYX_WEB_EVENT_RECORDS`, so the destination currently renders
`data-nyx-event-detail-missing` with **Event not found**. The named E2E can pass
this transition only by mocking the tonight response with a catalogue id. That
is valid component coverage, not proof that the production identifier join
works.

### 3. Use the working catalogue route

Open `/domains/nyx/events`, choose a listed event, and continue to its detail.
This route uses the same bundled catalogue as the resolver, so the id is valid.
Review the event copy, visibility guidance, calendar export, Tara relationship,
and observation entry point while keeping their independent state seams clear.

### 4. Save an observation

Submit the observation form. `useNyxStore` records local-first state and posts
to `/v1/nyx/observations`. The BFF is owner scoped and persists through Postgres
when configured or its supported file-snapshot fallback. The event id is
retained, and the rendered record shows **Linked event** as a tag. The tag does
not navigate back to event detail.

### 5. Verify projections and the Nisaba link

Reload Nyx or the relevant home rail and verify the saved observation projection
for the same account. The event's canon link to
`/nisaba?origin=nyx&topic=night-sky` is real navigation, but the compact Nisaba
room ignores those query parameters and opens its generic curated desk. It is
not a topic-resolved scholarly handoff.

## Post-conditions

- Live ephemeris facts are distinguished from the static event catalogue and
  illustrative sky art.
- A successful observation has owner-scoped BFF read-back, with local-first
  state reported separately if the network write fails.
- The compact-room id mismatch is preserved as an explicit product defect.
- The Nisaba destination is described as generic navigation, not as a resolved
  night-sky source chain.

## Failure modes

- **Tonight row 404-equivalent** — an ephemeris id reaches the event resolver
  and produces **Event not found**.
- **BFF unavailable** — the compact room uses the explicit unavailable state.
- **Chart overclaim** — hard-coded geometry or static compass chips are
  presented as live, oriented sensor output.
- **Observation divergence** — local state exists while the owner-scoped BFF
  write failed; a reload on another device will not prove persistence.
- **Broken association affordance** — **Linked event** looks actionable but is a
  non-link tag.
- **Generic scholar destination** — Nisaba receives query parameters it does not
  consume.

## E2E coverage

- [`apps/oshun/web/e2e/nyx-tonight-observation.spec.ts`](../../apps/oshun/web/e2e/nyx-tonight-observation.spec.ts)
  covers the journey anatomy; its mocked catalogue-compatible tonight id does
  not close the production id mismatch.
- [`apps/oshun/web/e2e/nyx-observations-bff.spec.ts`](../../apps/oshun/web/e2e/nyx-observations-bff.spec.ts)
  proves real observation write/read isolation.
- [`apps/oshun/web/e2e/nyx-event-pages.spec.ts`](../../apps/oshun/web/e2e/nyx-event-pages.spec.ts)
  covers the working catalogue detail route.
- [`apps/oshun/web/e2e/nyx-sky-almanac.spec.ts`](../../apps/oshun/web/e2e/nyx-sky-almanac.spec.ts)
  and
  [`apps/oshun/web/e2e/sky-text-nyx.spec.ts`](../../apps/oshun/web/e2e/sky-text-nyx.spec.ts)
  cover adjacent sky data and text.
- Coverage is **partial** until an unmocked live tonight id resolves into a
  valid detail and observation route.

## Per-view files touched

- [`customer/06-nyx/nyx.md`](../customer/06-nyx/nyx.md) — compact tonight room.
- [`customer/06-nyx/nyx-events.md`](../customer/06-nyx/nyx-events.md) — working
  event catalogue.
- [`customer/06-nyx/nyx-event-detail.md`](../customer/06-nyx/nyx-event-detail.md)
  — detail and missing-event states.
- [`customer/06-nyx/nyx-observation.md`](../customer/06-nyx/nyx-observation.md)
  — observation form and read-back.
- [`customer/07-nisaba/nisaba.md`](../customer/07-nisaba/nisaba.md) — generic
  scholar destination.

## Cross-references

- [`nyx-event-calendar-sync-reminder.md`](./nyx-event-calendar-sync-reminder.md)
  — event action and calendar boundaries.
- [`nyx-to-tara-bridge.md`](./nyx-to-tara-bridge.md) — static contemplative
  relationship.
- [`nisaba-scholarly-read.md`](./nisaba-scholarly-read.md) — compact Nisaba
  query-handling boundary.
- Code: `apps/oshun/bff/src/nyx/tonight-card.ts`,
  `apps/oshun/web/src/components/nyx/NyxRoom.tsx`, and
  `apps/oshun/web/src/lib/nyx-web-event-catalog.ts`.

## Open questions

- Should ephemeris rows resolve to generated detail models, or link somewhere
  other than the static event catalogue?
- Can a contract test require every `/v1/nyx/tonight` id to resolve through the
  web detail resolver?
- Which sky visualization elements should be driven by actual azimuth, altitude,
  time, and device orientation?
- Should observation associations be navigable in both directions?
- Should Nisaba consume `origin` and `topic`, or should Nyx link to a concrete
  passage/search route?
