diff options
Diffstat (limited to 'lib/rites/rite_ef')
| -rw-r--r-- | lib/rites/rite_ef/lectionary_ef.ml | 58 | ||||
| -rw-r--r-- | lib/rites/rite_ef/lectionary_ef.mli | 32 |
2 files changed, 69 insertions, 21 deletions
diff --git a/lib/rites/rite_ef/lectionary_ef.ml b/lib/rites/rite_ef/lectionary_ef.ml index d7b2497..4325bed 100644 --- a/lib/rites/rite_ef/lectionary_ef.ml +++ b/lib/rites/rite_ef/lectionary_ef.ml @@ -51,9 +51,9 @@ module Commons = struct | None -> ( (* A formulary with no citations is indistinguishable at the call site from "this saint has no Common" -- [commons_for] would - return [Some []] and [readings] would emit [] either way. That - is exactly the silent hole this project does not allow, so it - is rejected here where it is still nameable. *) + return [Some (common, [])] and [readings] would emit [] either + way. That is exactly the silent hole this project does not + allow, so it is rejected here where it is still nameable. *) match List.find_opt (fun (_, cs) -> cs = []) commons with | Some (s, _) -> Error (Printf.sprintf "commons: common %S has no citations" (Slug.to_string s)) @@ -72,10 +72,19 @@ module Commons = struct (Slug.to_string saint) (Slug.to_string common)) | None -> Ok { commons; assigned }))) + (* Returns the Common's own id ALONGSIDE its citations, not the citations + alone: [readings]' step 4 needs the id to build the day's + {!Colitur_kernel.Mass_formulary.t} ("the Common's own id as its slug"), + and the id is only ever in scope here, at the point [common] is looked + up -- re-deriving it afterwards would mean a second [assoc_opt] search + over [t.assigned] for a value this function already held. *) let find t saint = match List.assoc_opt saint t.assigned with | None -> None - | Some common -> List.assoc_opt common t.commons + | Some common -> ( + match List.assoc_opt common t.commons with + | None -> None + | Some cs -> Some (common, cs)) (* Byte-for-byte the failure discipline of [Lectionary.load] (see its own comments for why each catch-all is placed where it is): every parse and @@ -250,7 +259,8 @@ let is_bvm_saturday_office (observed : Vocab_ef.rank Celebration.t) let readings ~lectionary ~commons ~observed ~temporal ~date ~temporal_at = match observed.Celebration.citations with - | _ :: _ as cs -> cs + | _ :: _ as cs -> + (Some { Mass_formulary.said = observed.Celebration.slug; via = Mass_formulary.Proper }, cs) | [] -> ( (* Step 4: a saint who is the day's observed office and has no proper says his assigned Common. The assignment is explicit, never @@ -346,7 +356,8 @@ let readings ~lectionary ~commons ~observed ~temporal ~date ~temporal_at = match if sanctoral_office then commons_for ~commons observed.Celebration.slug else None with - | Some cs -> cs + | Some (common_id, cs) -> + (Some { Mass_formulary.said = common_id; via = Mass_formulary.Common }, cs) | None -> ( (* The votive Mass of Our Lady on Saturday (RG 309(a)) runs HERE: after the proper (step 1) and the Common (step 4), which answer @@ -354,13 +365,32 @@ let readings ~lectionary ~commons ~observed ~temporal ~date ~temporal_at = lookup -- which is exactly what used to answer, with the feria's own Mass, on a day whose office is Our Lady's. Placing it later would be dead code; placing it earlier would let it outrank a - real saint's proper. *) + real saint's proper. + + FORMULARY PROVENANCE, a genuine judgement call: {!Mass_formulary.source} + has no fifth constructor for "the RG 309(a) seasonal votive Mass", + so this is tagged [Own_slug] -- [is_bvm_saturday_office] only ever + fires when [sanctoral_office] above is false, i.e. the observed + celebration already IS the day's own temporal office (the office + deliberately reuses the ordinary ferial slug, [Temporal_ef]'s own + [bvm_saturday_names]), so [said] is genuinely "the day's own + slug" -- [Own_slug]'s own documented meaning + (mass_formulary.mli's [said] comment) -- even though the + citations themselves come from [bvm_saturday_citations]'s + season table rather than a [Lectionary.find] hit. Flagged in the + task report as an interpretation, not a specified answer. *) if is_bvm_saturday_office observed temporal then - bvm_saturday_citations temporal.Temporal.season ~month:(Date.month date) - ~day:(Date.day date) + let said = temporal.Temporal.office.Celebration.slug in + ( Some { Mass_formulary.said; via = Mass_formulary.Own_slug }, + bvm_saturday_citations temporal.Temporal.season ~month:(Date.month date) + ~day:(Date.day date) ) else match Lectionary.find lectionary temporal.Temporal.office.Celebration.slug with - | Some cs -> cs + | Some cs -> + ( Some + { Mass_formulary.said = temporal.Temporal.office.Celebration.slug; + via = Mass_formulary.Own_slug }, + 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 @@ -404,12 +434,14 @@ let readings ~lectionary ~commons ~observed ~temporal ~date ~temporal_at = 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 [] + if offset = 0 then (None, []) 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 -> []))) + | Some cs -> + let said = sunday_temporal.Temporal.office.Celebration.slug in + (Some { Mass_formulary.said; via = Mass_formulary.Preceding_sunday }, cs) + | None -> (None, [])))) diff --git a/lib/rites/rite_ef/lectionary_ef.mli b/lib/rites/rite_ef/lectionary_ef.mli index caefc74..2f36926 100644 --- a/lib/rites/rite_ef/lectionary_ef.mli +++ b/lib/rites/rite_ef/lectionary_ef.mli @@ -72,21 +72,28 @@ module Commons : sig val assignments : t -> (Slug.t * Slug.t) list end -(** The Common assigned to a saint who has no proper, if any. Exposed for the - golden pins, which must show WHICH Common fired, not merely that two - citations appeared. +(** The Common assigned to a saint who has no proper, if any -- its own id + ALONGSIDE its citations, not the citations alone: {!readings}' step 4 + needs the id to name which Common fired in the {!Colitur_kernel.Mass_formulary.t} + it builds. Exposed for the golden pins too, which must show WHICH Common + fired, not merely that two citations appeared. Takes the table explicitly for the same reason {!readings} takes [~lectionary]: the data is the caller's, not this module's. *) -val commons_for : commons:Commons.t -> Slug.t -> Citation.t list option +val commons_for : commons:Commons.t -> Slug.t -> (Slug.t * Citation.t list) option -(** The day's Epistle and Gospel citations, or []. +(** The Mass actually said -- which formulary, and how that was decided -- + paired with the day's Epistle and Gospel citations. [(None, [])] when + none of the four steps below answers. Four steps, in EXECUTION order 1, 4, 2, 3 (the numbers are the plan's and are kept as written, so that every "step 3" already recorded in a test - name, comment or report still means the same branch): + name, comment or report still means the same branch). Each step's own + {!Colitur_kernel.Mass_formulary.source} is built at the point the step + decides, not re-derived afterwards from the citations it returns: - {b Step 1} -- the observed celebration's own proper. + {!Colitur_kernel.Mass_formulary.Proper}, [said] the observed slug. - {b Step 4} -- a saint who is the day's observed office and has no proper says his assigned Common. Runs before the temporal fallbacks, not after them: this is the only step in the chain with a direct @@ -98,14 +105,23 @@ val commons_for : commons:Commons.t -> Slug.t -> Citation.t list option a feria, a Sunday, the Triduum and the RG 78 Saturday Office of the BVM (whose observed celebration is its own temporal office) are structurally excluded, not merely absent from the data. + {!Colitur_kernel.Mass_formulary.Common}, [said] the Common's own id. - {b Step 2} -- the day's own temporal slug in the lectionary. + {!Colitur_kernel.Mass_formulary.Own_slug}, [said] that slug. The RG + 309(a) Saturday votive Mass of Our Lady also answers here (structurally, + not as a fifth numbered step): it is tagged the same way, because its + own guard only ever fires when the observed celebration already IS the + day's own temporal office (the office reuses the ordinary ferial + slug) -- see the implementation comment on that branch. - {b Step 3} -- for a weekday whose own slug has no entry, the preceding Sunday's temporal slug (never its observed one; a Sunday is guarded out because it has no PRECEDING Sunday to resume, not because consulting itself would loop -- [readings] is not recursive, see its own implementation comment). + {!Colitur_kernel.Mass_formulary.Preceding_sunday}, [said] that + Sunday's temporal slug. - A day matching none of the four gets []. *) + A day matching none of the four gets [(None, [])]. *) val readings : lectionary:Lectionary.t -> commons:Commons.t -> @@ -113,4 +129,4 @@ val readings : temporal:(Vocab_ef.season, Vocab_ef.rank) Temporal.t -> date:Date.t -> temporal_at:(Date.t -> (Vocab_ef.season, Vocab_ef.rank) Temporal.t) -> - Citation.t list + Mass_formulary.t option * Citation.t list |
