Context. surface customer · domain nyx · route /domains/nyx/events · auth signed-in · source apps/oshun/web/src/app/domains/nyx/events/page.tsx
Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; live screen-reader, touch, offline, and telemetry-delivery checks pending a manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; content re-verified 2026-06-03 against current source
Purpose#
Canonical Nyx event calendar with cross-domain bridges — lists upcoming sky
events with importance filtering, Nisaba/Veritas/Tara/Concept-graph focus panels
for the lead event, and per-event save / follow / reminder / ICS calendar-export
actions. Page is a 'use client' shell
(apps/oshun/web/src/app/domains/nyx/events/page.tsx) that mounts
<EventCalendarOverlay onClose={() => router.replace('/domains/nyx?origin=explore')} origin="explore" stack={[]} />
under an sr-only <h1>Celestial Events · Nyx · OSHUN</h1>. The hydrated shell
variant at /domains/nyx?origin=...&path=%2Fevents closes by removing only the
path query while preserving origin and stack.
Entry points#
- Direct URL / bookmark — yes (signed-in)
- In-app navigation — verify the entry points (Nyx hub link, cross-domain explore rail)
- Event detail back-link —
NyxEventDetailWorkspaceshows "Return to Nyx events" →/domains/nyx?origin=explore&path=%2Fevents(so a detour through the domain root, not the/domains/nyx/eventsURL) - Close affordance — direct
/domains/nyx/eventsarrivals replace to the canonical/domains/nyx?origin=exploreshell; hydrated-shell arrivals remove onlypathand preserve the incoming shell context
Layout regions#
EventCalendarOverlay
(apps/oshun/web/src/components/domains/nyx/EventCalendarOverlay.tsx) renders
inside an OverlaySheet with variant="fullscreen",
title="Celestial Calendar",
description="Upcoming astronomical events and viewing windows."
sr-onlyheading: page-level<h1>Celestial Events · Nyx · OSHUN</h1>- OverlaySheet header: title + description + close button (sheet affordance)
- Timezone hint:
Times shown in: <Intl timezone> - Importance filter radio group: chips
All | Major | Notable | Minor(role="radiogroup",aria-label="Filter by importance") - Count line:
<N> event(s) SkyTextJourneyRail— cross-domain breadcrumb rail wired to the active stageopen-cosmology-and-texts("Open cosmology and texts"). The rail renders the four canonical stages in order: "Hold the sky moment", "Frame the observation", "Open cosmology and texts", and "Preserve the sky thread"; the active stage's primary action is "Open cosmology passage".- Nisaba overlay focus panel ("Nisaba overlay focus",
data-testid="nyx-calendar-nisaba-focus", ~190; iffocusEvent.nisabaOverlays.length > 0) - Veritas evidence focus panel ("Veritas evidence focus",
data-testid="nyx-calendar-veritas-focus", ~252; iffocusEvent.veritasExplainers.length > 0) - Tara perspective focus panel ("Tara perspective focus",
data-testid="nyx-calendar-tara-focus", ~310; iffocusEvent.taraRecommendations.length > 0) - Concept-graph focus panel ("Concept graph focus",
data-testid="nyx-calendar-concept-graph-focus", ~372; iffocusEvent.conceptGraphThreads.length > 0) - Event rows: each row shows time, importance pill, event-type chip, window/countdown/visibility line, summary, badges, action buttons, and a "View event page" link
States#
- Loading — bundled model from
listNyxEventPageModels(); no fetch - Populated (All filter) — every model returned by
listNyxEventPageModels({ origin, stack }) - Filtered (Major / Notable / Minor) — filter narrows the list
- Empty (filter excludes all) — count reads
0 events; verify empty state copy - Focus event with Nisaba overlays — Nisaba focus panel renders
- Focus event with Veritas explainers — Veritas focus panel renders
- Focus event with Tara recommendations — Tara perspective focus panel renders
- Focus event with concept-graph threads — Concept-graph focus panel renders
- Focus event with none of the above — each of the four focus panels is independently omitted when its array is empty
- Reminder enabled —
NyxEventReminderControls(compact) expands under the action row - Offline — static client computation; reminder/save state lives in
useNyxEventActionState(verify persistence) - Standalone PWA — overlay sheet covers full viewport
Interactions#
OverlaySheet chrome#
- Close button (sheet-level) —
nyx-full-journeyverifies direct-route close lands on/domains/nyx?origin=exploreand hydrated-shell close removespathwhile preservingorigin=home&stack=tara
Importance filter#
- "All" radio chip (
role="radio",aria-checked)- Function:
setFilter('All')
- Function:
- "Major" radio chip — colored with
var(--l-alert) - "Notable" radio chip — colored with
var(--l-warn) - "Minor" radio chip — colored with
L.muted
Focus panels#
-
SkyTextJourneyRail— cross-domain rail with stage labels fromOSHUN_SKY_TEXT_STAGE_MODEL: "Hold the sky moment", "Frame the observation", "Open cosmology and texts", and "Preserve the sky thread". Step action targets are produced byapps/oshun/web/src/navigation/sky-text-journey.ts:sky-nyx-nightly-highlights→ Nyx nightly highlights,sky-nyx-event-calendar→ Nyx events,sky-nyx-sky-map→ Nyx sky map,sky-nyx-observation-log→ Nyx observations,sky-nisaba-cosmology-passage→ Nisaba cosmology passage,sky-nisaba-calendar-source→ Nisaba calendar source,sky-nisaba-compare-texts→ Nisaba compare,sky-nisaba-notebook→ Nisaba notebook, andsky-library-save→ Library notebook filter. -
NisabaFocusLink(each overlay) — link to Nisaba surface -
VeritasFocusLink(each explainer) — link to a Veritas explainer -
TaraFocusLink(eachtaraRecommendationsentry) — link into a Tara practice -
ConceptGraphFocusThread(eachconceptGraphThreadsentry) — link into the cross-domain concept graph
Per-event row (each event in filteredEvents)#
- Importance pill — read-only badge with
event.importanceLabel - Event-type chip — read-only with
event.eventTypeLabel - Summary line —
event.windowLabel · event.countdownLabel · event.visibilityLabel - Save toggle (button,
data-testid="nyx-event-save-toggle-<eventId>")- Function:
toggleSaved— flips saved state - Label: "Save" → "Saved"
- Function:
- Follow toggle (button,
data-testid="nyx-event-follow-toggle-<eventId>")- Label: "Follow" → "Following"
- Reminder toggle (button,
data-testid="nyx-event-reminder-toggle-<eventId>")- Label: "Remind" → "Reminder on"
- "Add to Calendar (.ics)" button
- Function:
downloadNyxEventICalFile(event.eventId)— triggers ICS file download - Screen reader:
aria-label='Add "<event.title>" to calendar'
- Function:
- "View event page" link (
data-testid="nyx-event-open-<eventId>")- Function: navigates to
event.domainHref(/domains/nyx/events/<id>)
- Function: navigates to
- Reminder cadence + channels controls (when reminder enabled)
- Compact
NyxEventReminderControlswithsetReminderCadenceandsetReminderChannels
- Compact
Data & contracts#
- Reads:
listNyxEventPageModels({ origin, stack })fromnyxEventPageModels— bundled event index - Writes: ICS file download via
downloadNyxEventICalFile(eventId); save / follow / reminder state viauseNyxEventActionState(verify persistence: localStorage vs server) - Realtime: none
- Caching: client bundle, static
- Auth/role check: middleware enforces signed-in for
/domains/*
Cross-references#
- Detail view:
domains-nyx-events-eventId.md - Domain hub:
nyx.md - Component source:
apps/oshun/web/src/components/domains/nyx/EventCalendarOverlay.tsx - Model source:
apps/oshun/web/src/components/domains/nyx/nyxEventPageModels.ts - Action hook:
apps/oshun/web/src/components/domains/nyx/useNyxEventActionState.ts
Open questions / known gaps#
- Confirm whether save / follow / reminder state persists across reloads
(
useNyxEventActionStatestorage strategy) - Document the cross-domain bridge —
domainHreffrom the rail (the event domain target) versus/domains/nyx/events/[eventId]page - Confirm whether
OverlaySheetclose emits a route navigation or just hides the sheet — fixed and verified 2026-06-24. Direct route close replaces to/domains/nyx?origin=explore; hydrated shell close removes onlypathand keeps the rest of the shell context. - Verify whether unfiltered list contains a virtualized scroll for large catalogs