diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 08:49:57 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-07-28 08:49:57 +0200 |
| commit | 70b805018f0ae0d8424c3c7de8f1169476385a35 (patch) | |
| tree | 82de4bf52e588ab0c1f31ce0fc68d4b97b3d0de6 /internal/calendar/precedence.go | |
| parent | d3b7f41c7a823bda6b7bafae3a156348c4ce687f (diff) | |
| download | lectio-70b805018f0ae0d8424c3c7de8f1169476385a35.tar.gz lectio-70b805018f0ae0d8424c3c7de8f1169476385a35.zip | |
feat: complete OF+EF calendar coverage (movable feasts, vigils, ember days, transfers)
Ordinary Form:
- Add the movable Marian memorials that have no fixed date: Mary, Mother of the
Church (Monday after Pentecost) and the Immaculate Heart (Saturday after the
Sacred Heart), computed in computeOF.
- General Norms 60: two coinciding obligatory memorials both become optional and
the ferial is observed -- except Mary, Mother of the Church, which keeps
precedence per its 2018 decree.
Extraordinary Form:
- Capture fixed-date vigils in the sanctoral harvest (Christmas, the Nativity of
St John the Baptist, Sts Peter & Paul, St Lawrence, the Assumption, All Saints,
the Immaculate Conception) -- previously filtered out.
- temporalEF: the movable vigils of the Ascension (I class eve) and Pentecost
(Whitsun Eve), and the September/Advent Ember days (II class violet ferias).
- transferIfImpededEF: the Annunciation transfers past Holy Week/the Easter
octave to the Monday after Low Sunday; All Souls moves to Nov 3 when Nov 2 is a
Sunday.
- genlect harvests proper Masses for the new Ember/vigil days.
Adds TestEFCoverage + TestOFMovableMemorials. Bumps to 0.39.0.
Verified per-day: OF 0 real errors vs calapi (2026-2028, 100% correct-observed);
EF 0 real errors vs missalemeum (2025-2027), residual = deep-tail vigil-occurrence
and St Joseph Passiontide-transfer edges (~1-2 days/yr, documented).
Diffstat (limited to 'internal/calendar/precedence.go')
| -rw-r--r-- | internal/calendar/precedence.go | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/internal/calendar/precedence.go b/internal/calendar/precedence.go index 88cc0d8..3b7c0a6 100644 --- a/internal/calendar/precedence.go +++ b/internal/calendar/precedence.go @@ -84,5 +84,36 @@ func pick(cands []candidate) (candidate, []candidate) { } return sorted[i].Cel.Slug < sorted[j].Cel.Slug }) + // General Norms 60: when two obligatory memorials fall on the same day, both + // become optional and the weekday (ferial) is celebrated instead -- UNLESS one + // is Mary, Mother of the Church, whose 2018 institution decree gives it + // precedence over a coinciding obligatory memorial (then it is observed). + if len(sorted) >= 2 && !sorted[0].Temporal && !sorted[1].Temporal && + sorted[0].Cel.Rank == RankMemorial && sorted[1].Cel.Rank == RankMemorial { + if i := slugIndex(sorted, "mary-mother-of-the-church"); i >= 0 { + motc := sorted[i] + sorted = append(sorted[:i], sorted[i+1:]...) + sorted = append([]candidate{motc}, sorted...) + } else { + for i, c := range sorted { + if c.Temporal { + ferial := sorted[i] + sorted = append(sorted[:i], sorted[i+1:]...) + sorted = append([]candidate{ferial}, sorted...) + break + } + } + } + } return sorted[0], sorted[1:] } + +// slugIndex returns the position of the candidate with the given slug, or -1. +func slugIndex(cands []candidate, slug string) int { + for i, c := range cands { + if c.Cel.Slug == slug { + return i + } + } + return -1 +} |
