aboutsummaryrefslogtreecommitdiff
path: root/lib/rites/rite_of/vocab_of.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-25 15:35:59 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-25 15:35:59 +0200
commit6559a9b19451ce82a7d71281e25899acbcee2d49 (patch)
tree50474427ffa3f0403ce8f42998ec3aaf018af303 /lib/rites/rite_of/vocab_of.ml
parent73cdea4403e02e356e6eb2abaa7a96845d3b050c (diff)
downloadcolitur-6559a9b19451ce82a7d71281e25899acbcee2d49.tar.gz
colitur-6559a9b19451ce82a7d71281e25899acbcee2d49.zip
feat(of): Phase 1 of the OF rite module — vocab_of, temporal_of
The first code for a second rite. lib/rites/rite_of/vocab_of implements the OF's five-way rank vocabulary (Sollemnitas/Festum/Memoria_obligatoria/ Memoria_ad_libitum/Feria) and five-season vocabulary (Advent/Christmas/ Lent/Easter/Ordinary_time), each constructor cited against the 2002 Missale Romanum's Normae universales and the Tabula dierum liturgicorum. temporal_of implements season boundaries, week numbering — including Ordinary Time's own two-block resumption, derived from the Missale's own "HEBDOMADA I/XXXIV 'per annum'" headings and empirically verified across the whole 1583-9999 domain — named temporal days, and Sunday/ferial slugs. Both satisfy Colitur_kernel.Temporal.RITE with no kernel change. No Rite.t is assembled and no CLI wiring is added (Phase 2's own scope); lib/rites/rite_ef and data/ef are untouched, verified byte-identical against the v1.0.0 tag across a domain-spanning sample. test/test_temporal_of.ml adds unit tests for every boundary and named day plus seven QCheck properties (seasons contiguous, Ordinary Time weeks in 1..34, Advent always four Sundays, slug uniqueness, weekday agreement, determinism, consecutive liturgical years partition civil time), with a committed exhaustive sweep mirroring test_validate.ml's own convention. Full account, including the Ordinary Time derivation's evidence and a list of EF concepts that do not carry over, in .superpowers/sdd/of-phase1-report.md (untracked, gitignored).
Diffstat (limited to 'lib/rites/rite_of/vocab_of.ml')
-rw-r--r--lib/rites/rite_of/vocab_of.ml155
1 files changed, 155 insertions, 0 deletions
diff --git a/lib/rites/rite_of/vocab_of.ml b/lib/rites/rite_of/vocab_of.ml
new file mode 100644
index 0000000..932c30f
--- /dev/null
+++ b/lib/rites/rite_of/vocab_of.ml
@@ -0,0 +1,155 @@
+(* OF (post-1970) temporal cycle vocabulary. Both types are closed variants
+ private to this rite: EF code cannot name them, and this rite cannot name
+ EF's. Every boundary and rank rule cites its Missale Romanum editio typica
+ tertia (2002) "Normae universales de anno liturgico et de calendario"
+ paragraph ("Normae n. N") or Institutio Generalis Missalis Romani
+ paragraph ("IGMR n. N") -- the SAME PDF (docs/research/of/missale-
+ romanum-2002.pdf) carries both documents, independently numbered from 1,
+ so a bare "n. N" is ambiguous; every citation in this rite module names
+ which document it is. *)
+
+(* Normae Titulus II ("De anni circulo"), sections II-VI, PRIMARY-SOURCE-
+ VERIFIED against the 2002 typical edition (docs/research/of/
+ missale-romanum-2002.pdf, pdftotext -layout, around extracted line 3660
+ onward): the document's own six subsection headings under "De anni
+ circulo" are "I. De Triduo paschali", "II. De tempore paschali", "III. De
+ tempore Quadragesimae", "IV. De tempore Nativitatis", "V. De tempore
+ Adventus", "VI. De tempore 'per annum'". FIVE of those six are literally
+ called a "tempus" (season); the Triduum is deliberately NOT -- it is
+ named only "Triduum paschale", never "tempus Tridui". That is a real
+ textual signal, not an omission this module is working around: the
+ Missal's own authors did not count the Triduum as one of the seasons a
+ day's season vocabulary needs to name. Confirmed independently by the
+ Missal's own Mass-propers structure (extracted lines ~7778, ~8480):
+ "HEBDOMADA SANCTA" (the Lenten Holy Week propers) and "SACRUM TRIDUUM
+ PASCHALE" are printed as two SEPARATE section headings, and neither is
+ titled "tempus" either.
+
+ This module therefore has FIVE seasons, matching the design's own
+ prediction (2026-08-24-colitur-of-rite-module-design.md §4.2): [Advent],
+ [Christmas], [Lent], [Easter], [Ordinary_time]. No [Septuagesima] (the
+ 1969/2002 reform abolished the pre-Lent season the EF's Vocab_ef still
+ carries -- Normae's own season list has no seventh "de tempore
+ Septuagesimae" section at all, confirmed by its absence here) and no
+ [Passiontide] (EF's separate season for the two weeks before Easter; the
+ 2002 Normae's own n. 30 merges what used to be "Passion Sunday" and "Palm
+ Sunday" into ONE day, "Dominica in palmis de Passione Domini", and folds
+ it into Lent's own week numbering as week VI -- see [temporal_of.ml]'s own
+ citation on this for the full argument).
+
+ WHERE THE TRIDUUM'S OWN THREE DAYS LAND, given they get no season of
+ their own: Normae n. 28, PRIMARY TEXT: "Tempus Quadragesimae decurrit a
+ feria IV Cinerum ad Missam in Cena Domini EXCLUSIVE" -- Lent runs from Ash
+ Wednesday up to (excluding) the evening Mass of the Lord's Supper. At
+ colitur's own civil-day granularity (one season per [Date.t], never a
+ sub-day boundary), that puts the WHOLE civil day of Holy Thursday inside
+ Lent (the excluded boundary is the Mass itself, an event within that day,
+ not the day's own start). Good Friday and Holy Saturday have no season of
+ their own to fall back to either -- n. 22/23 fix Easter Time's own start
+ at "dominica Resurrectionis" (Easter SUNDAY), not a day earlier -- so by
+ the same "extend the last season through the Triduum's daytime, since the
+ only actual Mass in that window (the Vigil) is textually already Easter"
+ reasoning EF's own temporal_ef.ml already uses for its own Passiontide
+ ("Holy Saturday stays in Passiontide: the Vigil is a night Mass"), Good
+ Friday and Holy Saturday both stay [Lent] here too. Normae n. 30 gives
+ this a SECOND, independent, and more direct textual anchor unavailable to
+ EF's own analogous decision: "Dominicae huius temporis appellantur
+ dominicae I, II, III, IV, V in Quadragesima. Dominica sexta, in qua
+ initium sumit Hebdomada sancta, dicitur ... 'Dominica in palmis de
+ Passione Domini'" -- the Sundays of THIS TIME [Lent] are called Sundays
+ I-V in Lent; the SIXTH Sunday, ON WHICH HOLY WEEK BEGINS, is called
+ [without dropping the 'Alleluia', a rubric not relevant here] "Palm
+ Sunday of the Lord's Passion". Normae's OWN prose therefore states that
+ Holy Week (Palm Sunday through the Vigil) IS Lent's own sixth week, not a
+ thing outside Lent's own numbering -- confirmed against
+ [temporal_of.ml]'s own [week] computation, which independently derives
+ the identical result (Palm Sunday through Holy Saturday all fall in week
+ 6 of Lent by the ordinary Sunday-aligned [floor_div] formula, with no
+ special case needed for the Triduum days at all) -- see that file for the
+ arithmetic. *)
+type season = Advent | Christmas | Lent | Easter | Ordinary_time [@@deriving sexp]
+
+(* Normae Titulus I ("De diebus liturgicis"), and the Tabula dierum
+ liturgicorum's own 13-entry table (extracted lines ~3926-3980), name FOUR
+ graded celebrations throughout: "Sollemnitas" (entries 1-4), "Festum"
+ (entries 5-8), "Memoria obligatoria" (entries 10-11) and "Memoria ad
+ libitum" (entry 12) -- confirmed against the Calendarium Romanum
+ Generale's own printed month tables (e.g. "IN EPIPHANIA DOMINI
+ Sollemnitas", "S. Raimundi de Penyafort, presbyteri" [no grade word:
+ Memoria ad libitum by the table's own footnote, "Quando non indicatur
+ gradus celebrationis, fit Memoria ad libitum"], "Ss. Stephani,
+ protomartyris Festum"), which uses these four words as its own grade
+ column, verbatim, for every entry.
+
+ A FIFTH constructor, [Feria], is added beyond those four for an ordinary
+ weekday -- not a fifth grade on the same Sollemnitas-Festum-Memoria
+ scale, but a categorically different thing: Normae n. 16 (Titulus I.IV,
+ "De feriis") calls these days "feriae" and never applies any of the four
+ grade-words to one, yet {!Colitur_kernel.Celebration.t} requires SOME
+ [rank] on every day (the same reason EF's own Vocab_ef.rank carries a
+ catch-all [Class4] for its own plain ferias, RG 91 entry 28). The Tabula
+ itself confirms ferias are graded for PRECEDENCE without ever being
+ promoted to one of the four celebration-grades: entry 2 lists "Feriae
+ Hebdomadae sanctae, a feria II ad feriam V inclusive" and "Feria IV
+ Cinerum" [Ash Wednesday] at the SAME table position as Christmas,
+ Epiphany, Ascension and Pentecost -- an extremely privileged PRECEDENCE,
+ yet the table's own word for these days stays "feria", never
+ "sollemnitas". Entry 9 similarly places "Feriae Adventus a die 17 ad 24
+ decembris inclusive" and "Feriae Quadragesimae" together with a
+ THIRD kind of day (unnamed days within the Nativity octave), and entry 13
+ is the catch-all for every other feria. All THREE entries use the same
+ word, "feria" -- what differs between them is precedence-table position,
+ not grade. Phase 1 (this module, {!Temporal_of.temporal}) therefore
+ assigns [Feria] uniformly to every day carrying no graded celebration;
+ which Tabula entry a given [Feria] day occupies (Ash-Wednesday-tier vs.
+ Advent-17-24/Lenten-tier vs. ordinary) is a {!Colitur_kernel.Precedence
+ .rules.band} table lookup left to Phase 2, read off the day's own season/
+ date/weekday the same way EF's own [Precedence_ef.band] already
+ distinguishes its RG 91 entry 2 Triduum ferias from its entry-28 ordinary
+ ones without either of those two needing a DIFFERENT [Vocab_ef.rank]
+ value -- see design 2026-08-24-colitur-of-rite-module-design.md §3, "No
+ kernel change should be needed for the ranks themselves". *)
+type rank = Sollemnitas | Festum | Memoria_obligatoria | Memoria_ad_libitum | Feria [@@deriving sexp]
+
+let seasons = [ Advent; Christmas; Lent; Easter; Ordinary_time ]
+let ranks = [ Sollemnitas; Festum; Memoria_obligatoria; Memoria_ad_libitum; Feria ]
+
+let season_to_string = function
+ | Advent -> "advent"
+ | Christmas -> "christmas"
+ | Lent -> "lent"
+ | Easter -> "easter"
+ | Ordinary_time -> "ordinary-time"
+
+let season_of_string = function
+ | "advent" -> Some Advent
+ | "christmas" -> Some Christmas
+ | "lent" -> Some Lent
+ | "easter" -> Some Easter
+ | "ordinary-time" -> Some Ordinary_time
+ | _ -> None
+
+(* No lectionary-legacy word to preserve (spec §4.4's reasoning for EF's own
+ [Vocab_ef.season_slug_word] does not apply here -- OF has not been
+ bootstrapped from any external lectionary key set yet), so this is simply
+ [season_to_string] under a separate name, kept distinct only so a future
+ real divergence does not force renaming every call site. *)
+let season_slug_word = season_to_string
+
+let rank_to_string = function
+ | Sollemnitas -> "sollemnitas"
+ | Festum -> "festum"
+ | Memoria_obligatoria -> "memoria-obligatoria"
+ | Memoria_ad_libitum -> "memoria-ad-libitum"
+ | Feria -> "feria"
+
+let rank_of_string = function
+ | "sollemnitas" -> Some Sollemnitas
+ | "festum" -> Some Festum
+ | "memoria-obligatoria" -> Some Memoria_obligatoria
+ | "memoria-ad-libitum" -> Some Memoria_ad_libitum
+ | "feria" -> Some Feria
+ | _ -> None
+
+let vocab : (season, rank) Colitur_kernel.Vocab.t =
+ { seasons; season_to_string; season_of_string; ranks; rank_to_string; rank_of_string }