(** Resolution across a whole liturgical year (spec §2.4). Transfers make per-date resolution impossible to do correctly: resolving 25 March can push a feast onto 26 March, and RG 97-98 has coinciding I-class feasts transfer in table order, which needs global knowledge of the whole year. So [year] is the primitive -- it resolves every date in one pass -- and [day] is derived: it finds the liturgical year containing a date and indexes into it. Both are pure; neither caches. Once every day's temporal-vs-sanctoral contest is resolved, [year] places every deferred candidate (RG 96-98): a losing I-class candidate the rite's rules send to [Precedence.Transfer] does not stay put -- it moves to the next day [rite.transfer_target] names as admissible, and both ends of the move are recorded: [transferred_in] on the day it arrives (at most one -- RG 96 sends each departure to the next day that is not I or II class, and the first to arrive occupies it), [transferred_out] on the day it left (a list, not an option: RG 97-98 has coinciding I-class feasts transfer "in order", so one day can lose more than one). Every deferred candidate is accounted for exactly once: placed, or -- only if the placement fixed point is not reached within the round guard (which nothing in the 1962 calendar is expected to trigger), or the rite's own [transfer_target] names a date outside this liturgical year's own range (unproven to occur in the real EF calendar, but not ruled out by construction) -- left in [Liturgical_day.omitted] with a reason that says which, never silently dropped. See [calendar.ml]'s [place_transfers] for the algorithm and its termination argument. [Precedence.Repose]-disposed losers are gathered the same way [Precedence.Transfer]-disposed ones are (Precedence folds both into [deferred] as one case) and are routed through the same RG 96 search. That is only correct for [Transfer]: [Repose] denotes RG 100-102's *repositio*, a distinct rubric this module does not implement. Nothing in the EF ruleset currently returns [Repose] (design spec §1.3: "declared, not exercised" -- perpetual impediment arises from proper/diocesan calendars, out of this plan's scope), so the gap is latent rather than a live bug; documented here rather than given a second mechanism for a disposition nothing emits. *) (** [year rite layer y] resolves every day of the liturgical year that opens in civil year [y]: from [rite.year_start y] through the day before [rite.year_start (y + 1)], inclusive of both ends. Total over 1583..9999, including the boundary years, and beyond them too: [y] is clamped to [1582, 9999] before either bound is computed (not just guarded near the two edges independently -- see [year_bounds] in [calendar.ml] for why that distinction matters), so [year] never raises regardless of the [y] it is given, not only for values near the domain edge. - At [y] = 9999, [rite.year_start (y + 1)] would ask for civil year 10000, out of {!Date}'s domain (this is the bug Plan 2 shipped in [Validate] and later fixed). The end of the walk clamps to 31 December 9999 instead of computing that call; the returned year comes back truncated to whatever the rite's own temporal cycle covers between [rite.year_start 9999] and the last day of that civil year, not un-computable. - Symmetrically, [y] < 1583 clamps the start of the walk to 1 January 1583 instead of calling [rite.year_start y] on an out-of-domain civil year. [year] is never called this way directly by anything in this module; {!day} is the only caller that can reach [y] = 1582 (one below the floor, never lower), when the date it was asked about sits in civil year 1583 before that year's own [rite.year_start] -- i.e. the sliver whose true liturgical year opened in civil year 1582, which the domain cannot represent. Calling [year] with such a [y] directly is also safe: it returns exactly that truncated sliver. *) val year : ('s, 'r) Rite.t -> 'r Layer.t -> int -> ('s, 'r) Liturgical_day.t array (** [day rite layer date] finds the liturgical year containing [date] -- the year [y] with [rite.year_start y <= date < rite.year_start (y + 1)] -- and returns its slot for [date]. Recomputes that whole year on every call: pure, no cache, no mutable state. Acceptable cost for the natural usage (dump a year, sweep years for validation), which pays it once. *) val day : ('s, 'r) Rite.t -> 'r Layer.t -> Date.t -> ('s, 'r) Liturgical_day.t