aboutsummaryrefslogtreecommitdiff
path: root/docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md')
-rw-r--r--docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md92
1 files changed, 92 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md b/docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md
new file mode 100644
index 0000000..cf4749c
--- /dev/null
+++ b/docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md
@@ -0,0 +1,92 @@
+# OF Readings (Sundays + Solemnities) Implementation Design
+
+**Goal:** Make the Ordinary Form Sunday & solemnity readings computable offline — an embedded lectionary table keyed by the computed OF day identity (`<slug>-<cycle>`), generated once from niedziela, rendered from the public-domain corpora — so `lectio -L` and the JSON/iCal API serve OF readings without the scraper (Polish falling to Latin, exactly as EF does).
+
+**Architecture:** A new embedded `of-lectionary.ini` maps `<temporal-slug>-<SundayCycle>` → first/psalm/second/gospel citations (English-canonical). `caldata.Readings` gains an OF branch: inline propers → OF table lookup by `slug+cycle` → nil. A `//go:build ignore` generator (`scripts/genlect-of.go`) fetches niedziela over 2025-2027 (covering cycles A/B/C), extracts the per-part citations, normalizes them via the existing `bible.ToEnglishRef`, and keys them by the computed slug+cycle. Rendering reuses the existing `readingLine` (corpora + Latin fallback). This mirrors the EF readings pipeline exactly.
+
+**Tech Stack:** Go stdlib + `internal/ini`; reuses `internal/calendar`, `internal/caldata`, `internal/liturgy` (niedziela fetch/parse), `internal/bible` (ToEnglishRef, corpora). No new deps.
+
+## Global Constraints
+
+- **Scope THIS sub-project: Sundays + solemnities only.** The 3-year Sunday cycle (A/B/C) plus the solemnities/feasts that fall on or displace Sundays and carry proper readings. Weekdays (2-year I/II) and sanctoral memorials are OUT (later phases).
+- **Citations only, never text** (`references OK, translation copyrighted` — the standing principle). Citations stored English-canonical; text rendered from `drb`/`vul`; **Polish → Latin fallback** (bt copyrighted, `wuj` dropped) via the existing `readingLine` mechanism. A national-bibles Polish OF corpus could restore Polish text later, zero code.
+- **Keying:** `<Observed.Slug>-<SundayCycle>`, e.g. `lent-sunday-3-A`, `ordinary-sunday-10-B`, `christ-the-king-C`, `baptism-of-the-lord-A`. Uniform across temporal Sundays and Sunday-displacing solemnities (readings vary by cycle for many, so every entry is cycle-scoped; identical-across-cycle readings simply appear three times).
+- **Source:** niedziela.pl, harvested once over 2025-2027 (three civil years cover A/B/C). Credited in NOTICE alongside the existing niedziela attribution.
+- **Non-breaking:** the EF readings path, the niedziela daily-view scraper, `--liturgy`, and the API are unchanged; OF readings simply start resolving where they were empty.
+- **Purity preserved:** `internal/calendar` untouched (readings live in `caldata`); `caldata` imports only `calendar` + `ini` (+ `bible` already, for the generator's normalization the generator is `//go:build ignore` and may import more).
+
+## Detailed Design
+
+### 1. Keying scheme
+
+The OF engine already yields, per day: `Observed.Slug`, `Season`, `Week`, `SundayCycle` ("A"/"B"/"C"). The lectionary key is `Observed.Slug + "-" + SundayCycle`. Examples from the live engine:
+- `lent-sunday-3` + cycle A → `lent-sunday-3-A`
+- `ordinary-sunday-10` + A → `ordinary-sunday-10-A`
+- `easter-sunday` + A → `easter-sunday-A`
+- named solemnities: `christ-the-king-A`, `trinity-sunday-A`, `baptism-of-the-lord-A`, `palm-sunday-A`.
+
+Solemnities with truly fixed readings (rare) still get three identical cycle entries — simplest and robust; no special-casing.
+
+### 2. Data table: `internal/caldata/of-lectionary.ini`
+
+Same format as `tridentine-lectionary.ini`, keyed by `<slug>-<cycle>`:
+```ini
+; OF (Ordinary Form) Sunday & solemnity lectionary, keyed by
+; <computed-temporal-slug>-<SundayCycle>. Citations English-canonical.
+; Generated from niedziela.pl over 2025-2027. Text rendered from corpora.
+
+[ordinary-sunday-10-A]
+first = 1 Kgs 17:17-24
+psalm = Ps 30:2,4,5-6,11-12,13
+second = Gal 1:11-19
+gospel = Luke 7:11-17
+```
+`second` is omitted for the (few) Sundays without a second reading. Psalm citations are stored canonical; per-corpus psalm renumbering remains the deferred `psalm_system` work (§ EF spec) — best-effort until then.
+
+### 3. Generator: `scripts/genlect-of.go` (`//go:build ignore`)
+
+`go run scripts/genlect-of.go` (one-time, network):
+- Iterate EVERY day from 2025-01-01 to 2027-12-31 using `calendar.Compute` with a `Form="new"` selection. Keep a day if it is a **Sunday** OR its `Observed` is a **solemnity or feast of the Lord carrying proper readings** — including non-Sunday solemnities (Ascension, Corpus Christi, the Assumption, All Saints, the Immaculate Conception, etc.). `SundayCycle` is populated on those days too (verified: Assumption Sat 2026→A, Immaculate Conception Tue 2026→B), so they key uniformly by `slug+cycle`. Skip ordinary weekdays (the deferred weekday phase).
+- For each kept day, fetch niedziela via the existing modern-lectionary path (`readings.Load` with `lectionary=new`, or the underlying `liturgy` fetch) and read the sections' `Citation` per `PartID` (`pierwsze_czytanie`→first, `psalm`→psalm, `drugie_czytanie`→second, `ewangelia`→gospel).
+- Normalize each Polish-sigla citation to English-canonical with `bible.ToEnglishRef(cit, system)` (system per part: psalm→vulgate/drb as the existing code does; others default). Reuse the EF generator's `cleanCite` glitch-normalization.
+- Key by `Observed.Slug + "-" + SundayCycle`; write sorted into `of-lectionary.ini`. De-dup identical repeats across years (a given slug+cycle appears once).
+- Log coverage: entries written, any Sunday whose citations failed to parse (so gaps are visible, never silently dropped).
+
+### 4. Resolver extension: `caldata.Readings`
+
+Today `Readings(sel, layers, date, day)` returns inline propers, then `TemporalReadings(sel.Form, day.Observed.Slug)` (EF-only table), then the EF weekday fallback. Extend:
+- Add `var ofTempReadings = parseLectionary(ofLectionary)` (embedded `of-lectionary.ini`).
+- `TemporalReadings(form, key)`: `form=="old"` → `efTempReadings[key]`; else → `ofTempReadings[key]`.
+- In `Readings`, for the OF (`sel.Form != "old"`): after inline propers, look up `TemporalReadings("new", day.Observed.Slug + "-" + day.SundayCycle)`. (Weekdays — no `SundayCycle` — resolve to nothing for now; that is the deferred weekday phase.)
+- EF path unchanged.
+
+### 5. Rendering
+
+Unchanged: `cli.readingLine` parses the English-canonical citation (`ParseRef("en")`), displays in the configured sigla (`FormatRef`), and renders text from the reading corpus (`vernacularVersion` → drb for en, vul for others, with the Latin fallback). OF Polish therefore renders Latin until a Polish OF corpus is dropped in. The API/`-L` pick up OF readings automatically (they already call `caldata.Readings`).
+
+### 6. Validation
+
+- The OF **calendar** (season/week/cycle) is already oracle-validated vs calapi (0 season mismatches 2020-2040), so the KEYS are trustworthy.
+- **Readings**: since we generate from niedziela, correctness = (a) the generator captured each Sunday's four citations, and (b) they resolve. A test asserts a sample of well-known Sundays across A/B/C resolve to the expected pericope (e.g. Easter Sunday gospel John 20; Christ the King A = Matt 25:31-46). A coverage sweep asserts every Sunday of a sample year has a non-empty first+gospel.
+- No new oracle needed; the calendar oracle + a resolution sweep suffice.
+
+## Testing Approach
+
+- `internal/caldata`: `Readings` returns OF citations for a keyed Sunday (fixture table), empty for a weekday (deferred), and still returns EF readings unchanged; `TemporalReadings` form dispatch.
+- `internal/cli`: `lectio <of-sunday> -L` renders first+gospel for a 2026 Sunday (cycle A); Polish config renders Latin with the fallback note.
+- Coverage sweep (test or a scripted check): every Sunday of 2026 (cycle A) resolves a non-empty first + gospel; count and list any gaps.
+- The generator is `//go:build ignore` (not unit-tested); its output (`of-lectionary.ini`) is validated by the resolution sweep.
+
+## Out of Scope (YAGNI, later phases)
+
+- OF **weekdays** (2-year I/II cycle) — a follow-up, same pattern keyed by `<slug>-<weekday>-<WeekdayCycle>`.
+- OF **sanctoral** proper readings for individual memorials/feasts (non-Sunday).
+- Full scripture **text** in Polish (needs a Polish OF corpus; comes via national-bibles).
+- Retiring the niedziela daily-view scraper (separate "migrate daily view off scraper" work; OF-offline is a prerequisite, not part of this).
+- `psalm_system` application for OF psalm citations (deferred with the EF psalm work).
+
+## Open Decisions (resolved)
+
+- **Scope:** Sundays + solemnities first (weekdays later).
+- **Source:** niedziela.pl over 2025-2027, keyed by computed slug+cycle (the EF-genlect analog on the already-integrated, already-credited source).
+- **Polish text:** Latin fallback (consistent with EF; bt copyrighted, wuj dropped) — restorable later via a national-bibles Polish corpus.