aboutsummaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rites/rite_ef')
-rw-r--r--lib/rites/rite_ef/lectionary_ef.ml259
-rw-r--r--lib/rites/rite_ef/lectionary_ef.mli96
-rw-r--r--lib/rites/rite_ef/rite_ef.ml29
-rw-r--r--lib/rites/rite_ef/rite_ef.mli17
4 files changed, 319 insertions, 82 deletions
diff --git a/lib/rites/rite_ef/lectionary_ef.ml b/lib/rites/rite_ef/lectionary_ef.ml
index 37ec1d8..2658cd3 100644
--- a/lib/rites/rite_ef/lectionary_ef.ml
+++ b/lib/rites/rite_ef/lectionary_ef.ml
@@ -1,12 +1,116 @@
open Colitur_kernel
+(* The Commons of the 1962 Missal, plus the per-saint assignments that route
+ a readingless class-3 feast to one. Data only -- every value in the
+ shipped file is transcribed from the Missal and carries its own source
+ citation there (data/ef/commons.sexp). This module knows the SHAPE and
+ the invariants, never the values.
+
+ Caller-supplied, exactly as [lectionary] is, and for the same reason
+ (see this module's own .mli): a rite module that reads the filesystem as
+ a side effect of being linked breaks every caller that touches none of
+ its data. *)
+module Commons = struct
+ open Sexplib0.Sexp_conv
+
+ (* [commons]: a Common's id -> the Epistle and Gospel PRINTED WITH the
+ named Mass formulary. [assigned]: a saint's slug -> the Common his own
+ day sends him to. Two tables, not one, because the same Common serves
+ several saints and the two facts have different warrants -- the
+ formulary is read from the Commune Sanctorum, the assignment from the
+ saint's own date in the Proprium Sanctorum. *)
+ type t = {
+ commons : (Slug.t * Citation.t list) list;
+ assigned : (Slug.t * Slug.t) list;
+ }
+ [@@deriving sexp]
+
+ let empty = { commons = []; assigned = [] }
+ let formularies t = t.commons
+ let assignments t = t.assigned
+
+ (* Same discipline as [Colitur_kernel.Lectionary.of_entries]: canonically
+ sorted, and a duplicate key is an [Error] naming it rather than a
+ silently-shadowed second answer. *)
+ let sorted_by_slug xs = List.stable_sort (fun (a, _) (b, _) -> Slug.compare a b) xs
+
+ let first_dup xs =
+ let rec go = function
+ | (a, _) :: ((b, _) :: _ as rest) -> if Slug.equal a b then Some a else go rest
+ | _ -> None
+ in
+ go xs
+
+ let of_tables ~commons ~assigned =
+ let commons = sorted_by_slug commons and assigned = sorted_by_slug assigned in
+ match first_dup commons with
+ | Some s -> Error (Printf.sprintf "commons: duplicate common %S" (Slug.to_string s))
+ | None -> (
+ match first_dup assigned with
+ | Some s -> Error (Printf.sprintf "commons: duplicate assignment for %S" (Slug.to_string s))
+ | 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. *)
+ match List.find_opt (fun (_, cs) -> cs = []) commons with
+ | Some (s, _) ->
+ Error (Printf.sprintf "commons: common %S has no citations" (Slug.to_string s))
+ | None -> (
+ (* An assignment pointing at a Common that does not exist
+ would otherwise degrade to [None] -- i.e. to "this saint
+ has no Common", the same answer as no assignment at all --
+ so a typo in the data file would be invisible. Named
+ loudly instead. *)
+ match
+ List.find_opt (fun (_, common) -> not (List.mem_assoc common commons)) assigned
+ with
+ | Some (saint, common) ->
+ Error
+ (Printf.sprintf "commons: %S is assigned to unknown common %S"
+ (Slug.to_string saint) (Slug.to_string common))
+ | None -> Ok { commons; assigned })))
+
+ let find t saint =
+ match List.assoc_opt saint t.assigned with
+ | None -> None
+ | Some common -> List.assoc_opt common t.commons
+
+ (* 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
+ validation failure comes back as [Error], never as an exception, and
+ never at module-initialisation time. *)
+ let load path =
+ match Sexplib.Sexp.load_sexp path with
+ | exception Sexplib.Sexp.Parse_error e ->
+ Error (Printf.sprintf "commons: %s: %s" path e.err_msg)
+ | exception Sys_error e -> Error (Printf.sprintf "commons: %s" e)
+ | exception exn -> Error (Printf.sprintf "commons: %s: %s" path (Printexc.to_string exn))
+ | sexp -> (
+ match t_of_sexp sexp with
+ | exception Sexplib0.Sexp_conv_error.Of_sexp_error (exn, _) ->
+ Error (Printf.sprintf "commons: %s: %s" path (Printexc.to_string exn))
+ | exception exn -> Error (Printf.sprintf "commons: %s: %s" path (Printexc.to_string exn))
+ | parsed -> of_tables ~commons:parsed.commons ~assigned:parsed.assigned)
+end
+
+let commons_for ~commons saint = Commons.find commons saint
+
(* Step 1: the observed celebration's own proper.
+ Step 4: the observed SAINT's assigned Common -- see the branch comment in
+ [readings] for why it sits here, second, and not last.
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.
+ The steps keep their original NUMBERS (the plan's, and every existing
+ test's and comment's) even though step 4 now runs second: renumbering
+ would silently invalidate every "step 3" reference already written down.
+ Execution order is 1, 4, 2, 3.
+
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"
@@ -20,7 +124,9 @@ open Colitur_kernel
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. *)
+ itself, only [Lectionary.find]'s presence-or-absence as the mechanism.
+ Step 4 is the one step of the four that DOES have a direct primary-source
+ warrant; its own comment gives it. *)
(* 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
@@ -32,61 +138,110 @@ let days_since_sunday : Date.weekday -> int = function
| Date.Fri -> 5
| Date.Sat -> 6
-let readings ~lectionary ~observed ~temporal ~date ~temporal_at =
+let readings ~lectionary ~commons ~observed ~temporal ~date ~temporal_at =
match observed.Celebration.citations with
| _ :: _ as cs -> cs
| [] -> (
- match Lectionary.find lectionary temporal.Temporal.office.Celebration.slug with
+ (* Step 4: a saint who is the day's observed office and has no proper
+ says his assigned Common. The assignment is explicit, never
+ inferred -- see data/ef/commons.sexp.
+
+ ORDER. This runs SECOND, before the temporal fallbacks, not last as
+ the task brief sketched. The brief's ordering was tried first and is
+ provably dead code: measured against the real resolver over
+ 1950-2200, EVERY day on which one of the fifteen readingless
+ class-3 saints is actually the observed office also has a
+ non-empty step-2 or step-3 answer waiting (a Septuagesima or
+ Paschaltide feria resolves through its own slug or its preceding
+ Sunday's), so a step 4 placed after them is never reached on any
+ date in the domain. It would also be WRONG where it did fire: on
+ 2038-03-06 the observed office is Sts Perpetua and Felicity, a
+ III-class feast that beat the feria, and the Mass said that day is
+ theirs -- not Septuagesima II Saturday's 2 Cor 11:19-33 / Luke
+ 8:4-15, which is what the brief's ordering emits.
+
+ WARRANT, and it is the strongest in this chain: the Missal itself,
+ at each of these saints' own dates, names the Mass to be said --
+ "Missa Cognovi, de Communi non Virginum II loco, praeter orationem
+ sequentem" (9 March), "Missa Os iusti, de Communi Abbatum"
+ (21 March), and so on. That is a direct instruction about what is
+ read when the feast is the office of the day, quoted per saint in
+ data/ef/commons.sexp. Steps 2 and 3, by contrast, rest only on
+ lectio's observed behaviour (above). So the one step with a primary
+ source outranks the two without -- which is also simply what the
+ steps MEAN: steps 2 and 3 answer "what does this day's TEMPORAL
+ office read", a question that only governs when the temporal office
+ is the one being celebrated.
+
+ The guard makes that precondition structural rather than a property
+ of the data file: the Commons are consulted only when the observed
+ celebration is not itself the day's temporal office. Without it, a
+ future overlay that assigned a Common to a temporal slug by mistake
+ would silently replace a feria's Mass; with it, ferias, Sundays, the
+ Triduum and the RG 78 Saturday Office of the BVM (whose observed
+ celebration IS its temporal office, deliberately sharing the ferial
+ slug) can never be diverted here at all. [Validate] already asserts
+ slug uniqueness per liturgical year, so a sanctoral feast can never
+ collide with a temporal slug and be wrongly excluded by it. *)
+ let sanctoral_office =
+ not (Slug.equal observed.Celebration.slug temporal.Temporal.office.Celebration.slug)
+ in
+ match
+ if sanctoral_office then commons_for ~commons observed.Celebration.slug else None
+ 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.
+ 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.
+ 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 -> []))
+ 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 -> [])))
diff --git a/lib/rites/rite_ef/lectionary_ef.mli b/lib/rites/rite_ef/lectionary_ef.mli
index e54a0b1..baf25d4 100644
--- a/lib/rites/rite_ef/lectionary_ef.mli
+++ b/lib/rites/rite_ef/lectionary_ef.mli
@@ -3,12 +3,13 @@ open Colitur_kernel
(** The EF lectionary resolution chain. All rubric knowledge about what a day
with no proper falls back to lives here, not in the kernel.
- [lectionary] is caller-supplied, not loaded by this module -- the same
- reasoning rite_ef.mli's own [context] doc comment already gives for why
- the sanctoral {!Colitur_kernel.Layer.t} stays a separate argument rather
- than an embedded field: it lets a caller load data/ef/lectionary.sexp
- however suits it, and leaves room for a future diocesan/proper
- lectionary overlay to attach without this module changing at all.
+ [lectionary] and [commons] are both caller-supplied, not loaded by this
+ module -- the same reasoning rite_ef.mli's own [context] doc comment
+ already gives for why the sanctoral {!Colitur_kernel.Layer.t} stays a
+ separate argument rather than an embedded field: it lets a caller load
+ data/ef/lectionary.sexp and data/ef/commons.sexp however suits it, and
+ leaves room for a future diocesan/proper lectionary overlay to attach
+ without this module changing at all.
An eager filesystem read at module initialisation was tried first and
reverted (fix round 1, coordinator review): [readings] used to close
@@ -18,17 +19,84 @@ open Colitur_kernel
missing from a bare `dune build`'s own default target (it was only
present because test/dune's own deps happened to materialise it,
masking the gap in every test run). See the task report for the
- reproduction.
+ reproduction. The Commons follow the same path for the same reason. *)
- Steps 1-3 (Tasks 4-5): the observed celebration's own proper, else the
- day's own temporal slug in the lectionary, else -- 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). A day matching none of
- the three gets [] for now -- the Commons (Task 6) are not built here. *)
+(** The Commons of the 1962 Missal (Epistle and Gospel citations only) and
+ the per-saint assignments that route a readingless class-3 feast to one.
+
+ Two tables rather than one, because the two facts have different
+ warrants and different lifetimes: a FORMULARY is read from the Commune
+ Sanctorum and is the same for every saint sent to it, while an
+ ASSIGNMENT is read from one saint's own date in the Proprium Sanctorum.
+ A diocesan overlay adds assignments; it rarely adds formularies.
+
+ Assignment is explicit per saint, never inferred: {!Colitur_kernel.Subject.t}
+ is [Temporal|Saint|Bvm|Lord] and {!Colitur_kernel.Celebration.t} carries
+ no martyr/confessor/virgin/bishop/abbot classification at all, so there
+ is nothing to infer one from -- those words appear only inside display
+ names. A saint with no proper and no assignment gets no Common. *)
+module Commons : sig
+ type t
+
+ (** No formularies and no assignments -- the identity for this table, and
+ what a caller that genuinely has no Commons data should pass. Every
+ lookup returns [None]; nothing is silently invented. *)
+ val empty : t
+
+ (** Loads from a sexp file. Parse and validation failures come back as
+ [Error], never as an exception, and never at module-initialisation
+ time -- the same contract {!Colitur_kernel.Lectionary.load} makes.
+
+ [Error] (never a silently-degraded lookup) on: a duplicate common id;
+ a duplicate assignment for one saint; a formulary with no citations
+ (indistinguishable downstream from "no Common at all"); and an
+ assignment naming a common that does not exist (likewise). *)
+ val load : string -> (t, string) result
+
+ (** The Commons themselves, canonically sorted by id. *)
+ val formularies : t -> (Slug.t * Citation.t list) list
+
+ (** Saint slug -> common id, canonically sorted by saint. *)
+ 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.
+
+ 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
+
+(** The day's Epistle and Gospel citations, or [].
+
+ 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):
+
+ - {b Step 1} -- the observed celebration's own proper.
+ - {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
+ primary-source warrant (the Missal names the Mass at each such saint's
+ own date), and placing it last makes it unreachable on every date in
+ 1583-9999 as well as wrong on the days it would fire. The full
+ argument, with the measurement behind it, is on the branch itself.
+ Guarded so it can only ever apply to a SANCTORAL observed office --
+ 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.
+ - {b Step 2} -- the day's own temporal slug in the lectionary.
+ - {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).
+
+ A day matching none of the four gets []. *)
val readings :
lectionary:Lectionary.t ->
+ commons:Commons.t ->
observed:Vocab_ef.rank Celebration.t ->
temporal:(Vocab_ef.season, Vocab_ef.rank) Temporal.t ->
date:Date.t ->
diff --git a/lib/rites/rite_ef/rite_ef.ml b/lib/rites/rite_ef/rite_ef.ml
index ded960b..60065b7 100644
--- a/lib/rites/rite_ef/rite_ef.ml
+++ b/lib/rites/rite_ef/rite_ef.ml
@@ -11,16 +11,23 @@ module Lectionary_ef = Lectionary_ef
open Colitur_kernel
-(* [~lectionary], not a value closed over an internal load: fix round 1
- (coordinator review) found the previous version -- [context] as a plain
- value, [Lectionary_ef] loading data/ef/lectionary.sexp as a side effect
- of being linked -- made `colitur easter <year>` (no lectionary data
- touched at all) die at startup the moment that file was absent from a
- bare `dune build`'s own default target. A function mirrors how the
- sanctoral [Layer.t] already travels: caller-supplied, not embedded (see
- this module's own .mli doc comment on [context] for the fuller
- rationale, shared with data/ef/sanctoral.sexp). *)
-let context ~lectionary : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
+(* [~lectionary] and [~commons], not values closed over an internal load:
+ fix round 1 (coordinator review) found the previous version -- [context]
+ as a plain value, [Lectionary_ef] loading data/ef/lectionary.sexp as a
+ side effect of being linked -- made `colitur easter <year>` (no
+ lectionary data touched at all) die at startup the moment that file was
+ absent from a bare `dune build`'s own default target. A function mirrors
+ how the sanctoral [Layer.t] already travels: caller-supplied, not
+ embedded (see this module's own .mli doc comment on [context] for the
+ fuller rationale, shared with data/ef/sanctoral.sexp).
+
+ [~commons] is REQUIRED, not optional-with-a-default: an omitted
+ [?commons] would silently give a caller [Commons.empty], i.e. a rite
+ whose class-3 saints quietly lose their Mass, and nothing in the suite
+ compares citations across layers 3-5, so that loss would be invisible.
+ A caller that genuinely has no Commons data passes
+ [Lectionary_ef.Commons.empty] and says so. *)
+let context ~lectionary ~commons : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
{ Rite.id = Temporal_ef.id;
vocab = Vocab_ef.vocab;
year_start = Temporal_ef.year_start;
@@ -32,4 +39,4 @@ let context ~lectionary : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
admit = Precedence_ef.admit };
season_runs = Vocab_ef.seasons;
transfer_target = Precedence_ef.transfer_target;
- readings = Lectionary_ef.readings ~lectionary }
+ readings = Lectionary_ef.readings ~lectionary ~commons }
diff --git a/lib/rites/rite_ef/rite_ef.mli b/lib/rites/rite_ef/rite_ef.mli
index 12f5609..2183799 100644
--- a/lib/rites/rite_ef/rite_ef.mli
+++ b/lib/rites/rite_ef/rite_ef.mli
@@ -26,10 +26,12 @@ module Lectionary_ef = Lectionary_ef
value's own documentation for the termination and forward-progress
argument {!Colitur_kernel.Rite.t.transfer_target}'s contract requires).
- [readings]: {!Lectionary_ef.readings} partially applied to the caller's
- own [~lectionary] -- the observed celebration's own proper, else the
- day's own temporal slug, else (a weekday with no entry of its own) the
- preceding Sunday's temporal slug, in data/ef/lectionary.sexp (chain
- steps 1-3; the Commons are later work).
+ own [~lectionary] and [~commons] -- the observed celebration's own
+ proper, else (for a saint who is the day's observed office) his
+ assigned Common from data/ef/commons.sexp, else the day's own temporal
+ slug, else (a weekday with no entry of its own) the preceding Sunday's
+ temporal slug, in data/ef/lectionary.sexp. See {!Lectionary_ef.readings}
+ for why the Common is consulted second rather than last.
Deliberately carries no [sanctoral]/[lectionary] fields the way the
original design-doc sketch of [RITE] does: {!Colitur_kernel.Rite.t} (the
@@ -44,7 +46,12 @@ module Lectionary_ef = Lectionary_ef
that never touches lectionary data at all the moment that file was
missing from a bare build -- see the task report). A future
diocesan/proper lectionary overlay has a caller-side seam to attach to
- for the same reason the sanctoral overlay already does. *)
+ for the same reason the sanctoral overlay already does. [~commons]
+ travels the same seam, and is deliberately REQUIRED rather than
+ defaulted -- see this module's .ml for why a silently-defaulted
+ {!Lectionary_ef.Commons.empty} would be undetectable by any of the five
+ validation layers. *)
val context :
lectionary:Colitur_kernel.Lectionary.t ->
+ commons:Lectionary_ef.Commons.t ->
(Vocab_ef.season, Vocab_ef.rank) Colitur_kernel.Rite.t