(** The OF (post-1970) temporal cycle, per the Missale Romanum editio typica tertia (2002) "Normae universales de anno liturgico et de calendario" ("Normae n. N") and the Institutio Generalis Missalis Romani ("IGMR n. N") -- the same PDF carries both documents, independently numbered from 1, so every citation in this rite module names which one it is. OPEN QUESTION, deliberately NOT settled here (design 2026-08-24-colitur-of-rite-module-design.md ยง8.1): the OF calendar has no meaning before 1970, but colitur's kernel domain is 1583..9999, and this module is computable -- and computed -- across the WHOLE of it, exactly as {!Rite_ef.Temporal_ef} is. Phase 1 takes no position on whether a pre-1970 (or, symmetrically, a far-future) answer from this module means anything liturgically; it only guarantees the arithmetic is total and the properties below hold everywhere the kernel itself is total. Refusing, extrapolating, or flagging pre-1970 output specially is a decision for the phase that wires this module into a {!Colitur_kernel .Rite.t} and a validation layer with a real oracle to check it against -- not this one. *) open Colitur_kernel (** Normae n. 40: "Tempus Adventus incipit a I Vesperis dominicae quae incidit in diem 30 novembris vel est huic vicinior" -- Advent begins with First Vespers of the Sunday falling on 30 November or nearest to it. Worded identically in substance to EF's own RG 20 ({!Rite_ef.Temporal_ef .advent_start}), so the same closed-form identity applies: the Sunday nearest 30 November is, equivalently, three weeks before the last Sunday on or before 24 December -- see that function's own citation for why that identity holds for every civil year with no case split. *) val advent_start : int -> Date.t (** First day of the liturgical year opening in civil year [y]. Same as {!advent_start}. *) val year_start : int -> Date.t val season : Date.t -> Vocab_of.season (** Normae n. 38 and the Calendarium Romanum Generale's own January table (extracted line ~4033: "Dominica post diem 6 ianuarii: In baptismate Domini Festum"): the Sunday falling AFTER 6 January (never 6 January itself, even in a year 6 January IS a Sunday -- "post", not "on or after") carries the feast of the Baptism of the Lord. The January table's own further note ("Ubi sollemnitas Epiphaniae ad dominicam transfertur... festum Baptismatis Domini celebratur feria secunda sequenti") only concerns places that exercise Normae n. 37's LOCAL option to move Epiphany itself off 6 January -- inapplicable to the universal calendar this module computes, which keeps Epiphany fixed at 6 January (spec's own EF-precedented "universal calendar only" discipline), so that Monday-shift clause is never reached here. *) val baptism_of_the_lord : int -> Date.t (** Normae n. 35(a) and the December calendarium table's own closing line (extracted line ~4459: "Dominica infra octavam Nativitatis, vel, ea deficiente, die 30 decembris: Sanctae Familiae ... Festum"): the Sunday falling within the Octave of the Nativity (26-31 December), or, that lacking, 30 December. Movable-with-a-fixed-fallback, the same shape as EF's own Holy Family/Holy Name ({!Rite_ef.Temporal_ef.holy_family_sunday} /[holy_name_sunday]) -- CODE for that reason, not sanctoral DATA, unlike the plain fixed-date entries this window also contains (Stephen 26 Dec, John 27 Dec, the Holy Innocents 28 Dec), which carry no such fallback logic and are deferred to Phase 3's calendar data instead (see this file's own top-of-module comment for the full CODE-vs-DATA argument). UNLIKE EF's 7-13 January window, which can never be empty of a Sunday, this 6-day window (26-31 December) CAN be -- confirmed by the fallback clause's own existence in the primary text, not merely inferred. *) val holy_family : int -> Date.t (** Normae n. 36: "Dominica a die 2 ad diem 5 ianuarii occurrens est Dominica II post Nativitatem" -- the Sunday falling 2-5 January, if any, is the Second Sunday after the Nativity. [None] when no such Sunday exists that year (the SAME 2-5 January window as EF's own Holy Name of Jesus, {!Rite_ef.Temporal_ef.holy_name_sunday} -- a real structural coincidence between the two rites' calendars, not a shared computation: OF's Normae carries no "otherwise, on a fixed date" fallback for this Sunday at all, unlike EF's RG 17(a) -- a year without one simply has no "Second Sunday after the Nativity" office; {!temporal}'s own dispatch falls through to an ordinary Christmas-time feria for every day of that window in such a year). *) val second_sunday_of_christmas : int -> Date.t option (** Normae n. 43-44 and the Missale's own "HEBDOMADA XXXIV 'PER ANNUM'" heading (extracted line 13099: "Dominica ultima 'per annum' fit sollemnitas ... universorum Regis"): the LAST Sunday before Advent I, always the Solemnity of Christ the King, always week XXXIV. See {!temporal}'s own citation on the two-block week arithmetic for the full derivation this anchors. *) val christ_the_king : int -> Date.t (** The named temporal days: the Nativity and its Vigil, Mary Mother of God (the Nativity's own Octave Day, 1 January), Epiphany, Ash Wednesday, Palm/Passion Sunday, Easter and the days of its Octave, Ascension, Pentecost, Trinity Sunday, Corpus Christi, and Christ the King. Returns (season, slug, colour, rank). Carries no week of its own, for the same reason {!Rite_ef.Temporal_ef.named} does not: {!temporal} computes it uniformly via {!week} for every day, named or not, so a named day inside a numbered season run always carries that run's week. Deliberately EXCLUDES {!holy_family}, {!second_sunday_of_christmas} and {!baptism_of_the_lord}: each needs a per-year conditional ([holy_family] on whether 26-31 December has a Sunday at all; the other two on which Sunday, if any, actually falls in their own window) that this function's bare [Date.t -> ... option] shape has no way to express without threading extra state through every other branch too -- the exact reason EF's own [named] excludes its structurally identical Holy Family/Holy Name. {!temporal} applies all three as its own targeted dispatch instead. *) val named : Date.t -> (Vocab_of.season * string * Colour.t * Vocab_of.rank) option (** Week within the season, 1-indexed, Sunday-aligned (constant across a Sunday-to-Saturday span). [None] outside every numbered run -- Christmas has none at all (Normae's own Christmas-season structure is date-keyed, never week-keyed: contrast n. 36's "the Sunday falling 2-5 January", a date range, against n. 30's own "Sundays I, II, III..." for Lent) -- and Ordinary Time's own numbering is total over both of its runs (Normae n. 43-44): see {!temporal}'s own citation for the two-block arithmetic that makes the second run's numbers land correctly on 1..34 with the final week always 34, INCLUDING the "in some years a week is skipped entirely" case Normae n. 43's own "thirty-three OR thirty-four" already names. *) val week : Date.t -> int option (** The slug for a Sunday, or [None] if [d] is not a Sunday. *) val sunday_slug : Date.t -> string option val id : string (** Total over 1583..9999: every date yields exactly one temporal identity (subject to this file's own top-of-module note on what "yields" means before 1970). *) val temporal : Date.t -> (Vocab_of.season, Vocab_of.rank) Temporal.t (** Independent restatement of {!named}'s fixed and Easter-relative dates, plus {!holy_family}, {!second_sunday_of_christmas} and {!baptism_of_the_lord}, for civil year [y], paired with the slug each should carry -- the same anchor-agreement discipline {!Rite_ef.Temporal_ef.anchors} follows, for the same reason: catches an accidental single-site drift in an offset rather than leaving it invisible. Not wired into {!Colitur_kernel.Validate.run} in this phase (that needs a full {!Colitur_kernel.Rite.t}, Phase 2's own deliverable), but kept in the same shape so that wiring is a straight reuse. *) val anchors : int -> (string * Date.t) list