aboutsummaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef/lectionary_ef.ml
blob: 37ec1d874b2c22859c6ef56b88216b7e7e09dd15 (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
open Colitur_kernel

(* Step 1: the observed celebration's own proper.
   Step 2: the day's own temporal slug.
   Step 3: a weekday whose own slug has no entry says the preceding Sunday's
   Mass -- see the implementation comment on that branch in [readings] for
   the termination argument and why it is the Sunday's TEMPORAL, not
   observed, identity.

   Nothing here encodes "Lent has daily propers": the presence of an entry in
   [lectionary] is the sole discriminator -- this function does not branch on
   season, rank, or any other field to decide whether a temporal slug "ought"
   to have its own Mass.

   The WARRANT for that shape is lectio's own observed behaviour only, not a
   confirmed Missal citation: Lent 1 Monday returns its own Ezech 34:11-16,
   while Advent, Christmas and post-Pentecost Mondays return their Sunday's
   Mass, in both streams. docs/research/rules-register.md records this
   openly as unconfirmed against the primary source ("EF reading-selection
   rules ... Have lectio's behaviour; confirm against the Missal's
   ferial-Mass rubrics when coding") -- that confirmation has not been done;
   do not read this comment as citing RG/the Missal for the SELECTION rule
   itself, only [Lectionary.find]'s presence-or-absence as the mechanism. *)
(* Days from a given weekday back to the preceding Sunday. Sunday itself
   yields 0, which is why step 3 must guard on it -- see [readings] below. *)
let days_since_sunday : Date.weekday -> int = function
  | Date.Sun -> 0
  | Date.Mon -> 1
  | Date.Tue -> 2
  | Date.Wed -> 3
  | Date.Thu -> 4
  | Date.Fri -> 5
  | Date.Sat -> 6

let readings ~lectionary ~observed ~temporal ~date ~temporal_at =
  match observed.Celebration.citations with
  | _ :: _ as cs -> cs
  | [] -> (
      match Lectionary.find lectionary temporal.Temporal.office.Celebration.slug with
      | Some cs -> cs
      | None -> (
          (* Step 3: a feria with no proper of its own says the preceding
             Sunday's Mass. WARRANT is the same as step 2's -- lectio's own
             observed behaviour, not a confirmed Missal citation: this is the
             rule lectio hard-codes as data on the four Advent ferias
             (Advent II's readings copied verbatim onto the following
             Monday-Saturday) and leaves absent on the other slugs this step
             now also reaches; docs/research/rules-register.md already
             records the ferial-Mass selection rule itself as unconfirmed
             against the primary source.

             Guarded on weekday, but NOT because a Sunday reaching this
             branch would loop (fix round 1, coordinator review: the
             original comment here claimed exactly that, and it was wrong).
             [readings] is not recursive -- step 3's fallback is one flat
             [Lectionary.find], never a re-entrant call into [readings] --
             so without the guard, [days_since_sunday Sun = 0] would just
             repeat the SAME [Lectionary.find] step 2 already ran and
             already got [None] from (same pure inputs, same date), and
             return [] once, normally. The chain as a whole terminates
             because every step either consults data (a lookup) or, here,
             a strictly EARLIER date via [temporal_at] -- no step ever calls
             back into [readings] itself, so there is no recursion anywhere
             in this function for a cycle to form in the first place. The
             real reason for the guard is simpler: a Sunday has no
             PRECEDING Sunday to resume -- consulting itself would be
             meaningless (it would re-ask the question step 2 just
             answered), not dangerous, so the guard exists to make that
             intent explicit rather than to prevent a runaway loop that was
             never actually possible.

             The preceding Sunday's TEMPORAL slug, never its observed one:
             the rubric is the preceding Sunday's Mass even in a year when a
             feast displaced that Sunday from being observed (see
             test_step3_uses_temporal_not_observed). [temporal_at] gives the
             temporal identity of any date, so the Sunday is reached by date
             arithmetic and a fresh call to the temporal cycle -- never by
             string surgery on [own_slug]: the slug shapes are genuinely
             inconsistent across seasons (e.g. [ef-advent-sunday-1] versus
             [ef-advent-1-monday], the week number on opposite sides of the
             season name), so deriving one from the other textually would be
             a latent bug the moment a season's naming convention differs. *)
          let offset = days_since_sunday temporal.Temporal.weekday in
          if offset = 0 then []
          else
            let sunday = Date.add_days date (-offset) in
            let sunday_temporal = temporal_at sunday in
            match
              Lectionary.find lectionary sunday_temporal.Temporal.office.Celebration.slug
            with
            | Some cs -> cs
            | None -> []))