aboutsummaryrefslogtreecommitdiff
path: root/docs/superpowers/specs/2026-07-27-lectio-of-readings-design.md
blob: cf4749cfdd45428563caff0d7988e3c73803389e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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.