Skip to main content

Living Word — Live-Ops Phase 1A

What shipped

The Phase 1A slice of knowledge/acceptance/living-word-liveops-phase1.md §12:

  1. Server-side liturgical calendar enginesrc/lib/living-word/calendar.ts

    • computeWesternEaster(year) implements the Anonymous Gregorian Algorithm (Computus); deterministic, no external library.
    • resolveActiveEvent(date, traditionLensId?) returns the single active event (with specificity-based overlap resolution) plus the next 3 upcoming events.
    • Hand-verified for Easter dates 2025-2035 (48 unit tests, all green).
  2. Three-feast default ON for every player — Christmas (Dec 25 - Jan 5), Easter Sunday + Eastertide (50 days), Pentecost. All universal scope — visible regardless of tradition lens.

  3. Lens-gated full Western calendar — Advent, Lent, Christ the King surface only when the player's lens is Catholic (7), Lutheran (6), Methodist / Wesleyan (5), Anglican (13), or Eastern Orthodox (11). The gated lens set is encoded as WESTERN_LITURGICAL_LENS_IDS and asserted in the test suite to guard against silent drift.

  4. HUD chipCalendarEventChip.tsx sits beside the existing FiveActsHudChip in the top-left HUD. Hidden when no event is active or the player has opted out. Click opens the modal.

  5. CalendarEventModal — narrator-voice copy for each of the 8 seasons. Tradition-neutral by default. Shows event name, date range, scripture anchor, contemplative paragraph, next-3 upcoming events, opt-out link.

  6. Per-event opt-out — new table lw_player_calendar_prefs (RLS; player-owned). Supports exact event-id opt-out (christmas-2026) or wildcard family opt-out (christmas-*). API at /api/living-word/calendar-prefs.

  7. Voice-rule lintscripts/living-word/voice-rule-check.mjs greps src/app/living-word/ + src/lib/living-word/ for the banned root "evolv". Exits non-zero on match. Currently clean across all Living Word surfaces.

  8. Full Phase 1 schema migration2026-05-24-lw-events-and-streaks.sql created all four tables in one shot per spec §12 (avoids a second migration when Phase 1B + 1C land):

    • lw_player_calendar_prefs (used today)
    • lw_player_streaks (Phase 1B will wire)
    • lw_streak_events (Phase 1B will wire)
    • lw_event_completions (Phase 1C will wire)

Deferred (per spec)

  • Phase 1B — streak telemetry foundation. The schema is in place; the StreakDisplay UI extension and /api/living-word/streaks/* endpoints are the next slice.
  • Phase 1C — Holy Week six-scene event. Blocked on founder content authoring (per the handoff doc, Phase C).
  • Eastern Orthodox calendar (Phase 2). Phase 1A's Orthodox lens reads the Western calendar with a flagged TODO; Pascha (Julian) math lands in Phase 2.
  • Push notifications of any kind. Phase 3 minimum.

Verification evidence

  • Unit tests. 48 tests in src/lib/living-word/__tests__/calendar.test.ts, all passing. Covers Computus correctness 2025-2035, First Sunday of Advent + Christ the King, three-feast lens-blind surfacing, lens-gating on Ash Wednesday + Advent + Christ the King, overlap resolution (Easter > Eastertide; Pentecost > Eastertide; Lent during ordinary days for Catholic lens), upcoming-list cardinality + ordering, pattern matching.
  • Playwright spec. 26 tests in e2e/living-word/liveops-phase1a.spec.ts, all passing on a freshly deployed dev server. Verifies the API contract for every Western-liturgical lens + the chip/modal browser flow + 401 auth boundary on opt-out endpoint.
  • Voice-rule lint. Clean across all Living Word source surfaces.
  • Build. pnpm build compiles successfully.

Founder follow-ups (per spec §15 + handoff §3)

  • Apply the migration (already applied via Supabase MCP on 2026-05-24).
  • Personally approve all calendar event modal copy (8 seasons of narrator paragraphs) — see src/app/living-word/components/CalendarEventModal.tsx EVENT_COPY object.
  • Pre-commit to streaks-default rule for Phase 1B (recommendation: ON with prominent opt-out).
  • Pre-commit to Phase 1C slip-date decision rule (Triduum fallback vs. hold for 2028) by mid-January 2027.

Operational notes

  • The /api/living-word/events/active endpoint accepts optional ?date=YYYY-MM-DD and ?lensId=N query params. Anonymous players hit it without auth and see universal feasts only. Authenticated players additionally have their lw_player_calendar_prefs opt-outs applied.
  • The chip also supports ?lwTestDate=YYYY-MM-DD and ?lwTestLens=N URL parameters on /living-word itself — used by Playwright to mock any liturgical date + lens combination without authenticating or mutating server state. In production these params are harmless.
  • Per-event opt-out persists across sessions via lw_player_calendar_prefs (authenticated) only. Phase 2 will add anonymous opt-out via localStorage.