aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/kernel/rite.ml1
-rw-r--r--lib/kernel/rite.mli36
-rw-r--r--lib/kernel/validate.ml31
-rw-r--r--lib/kernel/validate.mli22
-rw-r--r--lib/rites/rite_ef/rite_ef.ml7
-rw-r--r--lib/rites/rite_ef/rite_ef.mli5
-rw-r--r--lib/rites/rite_of/rite_of.ml13
-rw-r--r--lib/rites/rite_of/rite_of.mli7
8 files changed, 99 insertions, 23 deletions
diff --git a/lib/kernel/rite.ml b/lib/kernel/rite.ml
index e44c2c6..adca8fe 100644
--- a/lib/kernel/rite.ml
+++ b/lib/kernel/rite.ml
@@ -19,6 +19,7 @@ type ('s, 'r) t = {
date:Date.t ->
temporal_at:(Date.t -> ('s, 'r) Temporal.t) ->
Mass_formulary.t option * Citation.t list;
+ citation_shapes : Citation.part list list;
creed : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> bool;
gloria : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> bool;
preface : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> Preface.t option;
diff --git a/lib/kernel/rite.mli b/lib/kernel/rite.mli
index d53e4e6..ec850f8 100644
--- a/lib/kernel/rite.mli
+++ b/lib/kernel/rite.mli
@@ -100,10 +100,12 @@ type ('s, 'r) t = {
temporal_at:(Date.t -> ('s, 'r) Temporal.t) ->
Mass_formulary.t option * Citation.t list;
(** The Mass actually said -- which formulary, and how that was decided
- -- paired with its Epistle and Gospel citations. Rite-supplied for
- the same reason [transfer_target] is: what a day with no proper of
- its own falls back to is a rubric of a particular rite, not a
- universal.
+ -- paired with its reading citations (EF: Epistle and Gospel; OF:
+ First, and on Sundays/solemnities also Second, and Gospel -- see
+ {!citation_shapes} for the rite-supplied shape [Validate] holds
+ this list to). Rite-supplied for the same reason [transfer_target]
+ is: what a day with no proper of its own falls back to is a rubric
+ of a particular rite, not a universal.
The [Mass_formulary.t option] is [None] exactly when the rite's
lectionary is not built at all (the citation list is then also
@@ -119,6 +121,32 @@ type ('s, 'r) t = {
temporal identity (the preceding Sunday's, for the ferial rule)
without re-implementing the temporal cycle -- the same shape
[transfer_target]'s own [occupant] callback established. *)
+ citation_shapes : Citation.part list list;
+ (** Every well-formed shape a resolved day's [citations] may take, each
+ already sorted in {!Citation.part}'s own declaration order (the
+ order [List.sort compare] gives it, and the order {!Validate}'s own
+ ["citations"] check sorts a day's actual parts into before
+ comparing). A day passes that check when its sorted parts are
+ EMPTY (nothing resolved -- the separate ["citations-unresolved"]
+ coverage check) or equal one of these shapes EXACTLY -- no more
+ parts, no fewer, none repeated.
+
+ Generalises what used to be a single kernel-hardcoded
+ [[First; Gospel]], the fourth EF-shaped kernel misfit (after
+ {!Preface.t}, {!Mass_formulary.source}, [transfer_target]'s
+ strictly-later contract) and the first fixed rather than only
+ documented: the OF's Mass has TWO legitimate sizes, not one --
+ [[First; Gospel]] on a feria, feast or memorial, and
+ [[First; Second; Gospel]] on a Sunday or solemnity (OLM 1981
+ Praenotanda n. 66.1 vs n. 69.1, page-image verified,
+ docs/research/of/olm-1981.pdf pp.32-33/"XXXII-XXXIII": "Quaelibet
+ Missa tres exhibet lectiones" against "Quaelibet Missa duas
+ exhibet lectiones"; n. 84(b)/(c), pp.37-38/"XXXVII-XXXVIII",
+ extends the three-reading shape to every solemnity of a
+ particular calendar and confines feasts/memorials to two). EF
+ still supplies exactly the one shape it always had -- see
+ rite_ef.ml's own [citation_shapes] -- so EF's resolved output is
+ unaffected letter for letter. *)
creed : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> bool;
(** Whether the Creed is said, post-Gospel/homily, at this day's Mass
(EF: RG 475-476). A [bool], not an [option]: this is a decision,
diff --git a/lib/kernel/validate.ml b/lib/kernel/validate.ml
index f523b39..c7b6093 100644
--- a/lib/kernel/validate.ml
+++ b/lib/kernel/validate.ml
@@ -414,18 +414,26 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
is why it is a match on the sorted part list rather than three
separate tests:
- - zero or two, never one -- an Epistle without a Gospel, or the
- reverse, is a malformed Mass, not a partial one;
- - only [First] and [Gospel] ever appear -- the chants (Psalm,
- Second, Tract, Alleluia, Sequence) are deliberately unbuilt,
- with no source and no oracle, so a citation carrying one is a
- defect and not a feature arriving early;
+ - zero, or exactly one of the rite's own well-formed shapes,
+ never a partial one -- an Epistle without a Gospel, or the
+ reverse, is a malformed Mass regardless of which shapes the
+ rite declares;
+ - no part outside the rite's own {!Rite.t.citation_shapes} ever
+ appears -- for EF that is still only [First]/[Gospel] (the
+ other chants remain deliberately unbuilt there, with no
+ source and no oracle, so one appearing is a defect, not a
+ feature arriving early); for the OF it is [First]/[Second]/
+ [Gospel], [Second] only ever alongside both of the others (its
+ own doc comment has the full citation and argument);
- no part appears twice -- two Epistles and no Gospel has length
two and would slip past a bare cardinality test.
- [Citation.part]'s own constructor order puts [First] before
- [Gospel], so the sorted well-formed list is literally
- [[First; Gospel]] and nothing else. *)
+ Each of [rite.Rite.citation_shapes]'s own shapes is normalised
+ with the SAME [List.sort compare] a day's actual parts are put
+ through, so a rite may list them in any order without silently
+ failing to match -- robustness the single hardcoded
+ [[First; Gospel]] this replaced never needed to worry about. *)
+ let citation_shapes = List.map (List.sort compare) rite.Rite.citation_shapes in
let year_has_citations =
Array.exists
(fun (d : ('s, 'r) Liturgical_day.t) -> d.Liturgical_day.citations <> [])
@@ -439,7 +447,6 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
List.map (fun (c : Citation.t) -> c.Citation.part) d.Liturgical_day.citations
in
match List.sort compare parts with
- | [ Citation.First; Citation.Gospel ] -> ()
| [] ->
(* Separate check name from the malformed case below on
purpose: this is the lectionary chain falling through
@@ -449,9 +456,11 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
fail date "citations-unresolved"
"no reading citations resolved for this day: the lectionary chain fell through \
every step"
+ | sorted when List.mem sorted citation_shapes -> ()
| sorted ->
fail date "citations"
- (Printf.sprintf "expected exactly one First and one Gospel, got [%s]"
+ (Printf.sprintf
+ "citation parts [%s] match none of this rite's own well-formed shapes"
(String.concat "," (List.map Citation.part_to_string sorted))))
resolved;
(* ---- Formulary invariant (Task 3, celebrant-rubrics-phase1) ----
diff --git a/lib/kernel/validate.mli b/lib/kernel/validate.mli
index 385e111..9ad6b59 100644
--- a/lib/kernel/validate.mli
+++ b/lib/kernel/validate.mli
@@ -84,14 +84,20 @@ val failure_to_string : failure -> string
{!Rite.readings} on every day and is held to neither, so this stays a
check on rites that HAVE readings rather than a demand that every rite
have them.
- - ["citations"]: well-formedness. A day's citation parts, sorted, are
- exactly [[First; Gospel]]. This single condition carries three
- invariants at once: zero or two but never one (an Epistle without a
- Gospel, or the reverse, is a malformed Mass rather than a partial one);
- no part outside [First]/[Gospel] (the chants -- Psalm, Second, Tract,
- Alleluia, Sequence -- are deliberately unbuilt, so one appearing is a
- defect, not a feature arriving early); and no part twice (two Epistles
- and no Gospel has length two and would pass a bare cardinality test).
+ - ["citations"]: well-formedness. A day's citation parts, sorted, must be
+ either empty or equal ONE of [rite.Rite.citation_shapes] exactly --
+ rite-supplied ({!Rite.t.citation_shapes}'s own doc comment has the
+ full citation and argument for why: EF has one shape, [[First;
+ Gospel]]; the OF has two, that same pair plus [[First; Second;
+ Gospel]] on Sundays/solemnities). This single condition carries three
+ invariants at once: zero, or exactly one of the rite's own complete
+ shapes, never a partial one (an Epistle without a Gospel, or the
+ reverse, is a malformed Mass under any rite's shape list); no part
+ outside what the rite itself declares (EF: the other chants remain
+ deliberately unbuilt, so one appearing is a defect, not a feature
+ arriving early); and no part twice (two Epistles and no Gospel has
+ length two and would pass a bare cardinality test, but matches none of
+ a rite's own declared shapes).
- ["citations-unresolved"]: coverage. A day resolved NO citations at all,
i.e. the rite's own lookup chain fell through every one of its steps.
Deliberately a separate label from ["citations"] above: a coverage gap
diff --git a/lib/rites/rite_ef/rite_ef.ml b/lib/rites/rite_ef/rite_ef.ml
index 808e017..8efcbfd 100644
--- a/lib/rites/rite_ef/rite_ef.ml
+++ b/lib/rites/rite_ef/rite_ef.ml
@@ -51,6 +51,13 @@ let context ~lectionary ~commons : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
season_runs = Vocab_ef.seasons;
transfer_target = Precedence_ef.transfer_target;
readings = Lectionary_ef.readings ~lectionary ~commons;
+ (* The one shape the EF Mass has ever had: an Epistle and a Gospel,
+ nothing else (RG carries no Second-reading or responsorial-psalm
+ structure -- that is an OF/OLM 1981 innovation, {!Rite.t
+ .citation_shapes}'s own doc comment has the citation). Kept as the
+ single-element list it always implicitly was before this field
+ existed, so EF's resolved output is unaffected letter for letter. *)
+ citation_shapes = [ [ Citation.First; Citation.Gospel ] ];
creed = Rubrics_ef.creed;
gloria = Rubrics_ef.gloria;
preface = Rubrics_ef.preface }
diff --git a/lib/rites/rite_ef/rite_ef.mli b/lib/rites/rite_ef/rite_ef.mli
index 2ed61de..304bcb6 100644
--- a/lib/rites/rite_ef/rite_ef.mli
+++ b/lib/rites/rite_ef/rite_ef.mli
@@ -33,6 +33,11 @@ module Rubrics_ef = Rubrics_ef
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.
+ - [citation_shapes]: the single [[First; Gospel]] shape the EF Mass has
+ always had -- see {!Colitur_kernel.Rite.t.citation_shapes}'s own doc
+ comment for why this is now rite-supplied (the OF needs a second
+ shape) rather than a kernel constant, and this file's own [context]
+ for why EF's own resolved output is unaffected letter for letter.
- [creed]: {!Rubrics_ef.creed}, RG 475-476 -- whether the Creed is said.
The first rubric in this phase governing a part of Mass rather than
occurrence/precedence.
diff --git a/lib/rites/rite_of/rite_of.ml b/lib/rites/rite_of/rite_of.ml
index 9eeb5ef..f45bf50 100644
--- a/lib/rites/rite_of/rite_of.ml
+++ b/lib/rites/rite_of/rite_of.ml
@@ -80,6 +80,19 @@ let context ~lectionary : (Vocab_of.season, Vocab_of.rank) Rite.t =
season_runs = Vocab_of.[ Advent; Christmas; Ordinary_time; Lent; Easter; Ordinary_time ];
transfer_target = Precedence_of.transfer_target;
readings = Lectionary_of.readings ~lectionary ~year_start:Temporal_of.year_start;
+ (* Two well-formed shapes, not EF's one -- OLM 1981 Praenotanda n. 66.1
+ ("Quaelibet Missa tres exhibet lectiones": Sunday/solemnity Mass,
+ First from the OT, Second "ex Apostolo", Gospel) against n. 69.1
+ ("Quaelibet Missa duas exhibet lectiones": ferial Mass, First and
+ Gospel only), both page-image verified,
+ docs/research/of/olm-1981.pdf pp.32-33/"XXXII-XXXIII"; n. 84(b)/(c),
+ pp.37-38/"XXXVII-XXXVIII", extends the three-reading shape to every
+ solemnity of a particular calendar and confines feasts/memorials to
+ two. {!Rite.t.citation_shapes}'s own doc comment has the fuller
+ argument for why this is a rite-supplied field rather than a kernel
+ constant. *)
+ citation_shapes =
+ [ [ Citation.First; Citation.Gospel ]; [ Citation.First; Citation.Second; Citation.Gospel ] ];
creed = Rubrics_of.creed;
gloria = Rubrics_of.gloria;
preface = Rubrics_of.preface }
diff --git a/lib/rites/rite_of/rite_of.mli b/lib/rites/rite_of/rite_of.mli
index eeb38d5..8124467 100644
--- a/lib/rites/rite_of/rite_of.mli
+++ b/lib/rites/rite_of/rite_of.mli
@@ -43,6 +43,13 @@ module Lectionary_of = Lectionary_of
reading-cycle arithmetic's own Advent anchor) -- no [~commons]
parameter, unlike EF: the OF lectionary chain has no Commons
indirection to thread through.
+ - [citation_shapes]: TWO well-formed shapes, not EF's one --
+ [[First; Gospel]] on a feria, feast or memorial, and
+ [[First; Second; Gospel]] on a Sunday or solemnity (OLM 1981
+ Praenotanda n. 66.1/n. 69.1, n. 84(b)/(c)) -- see this file's own
+ [context] for the full citation and
+ {!Colitur_kernel.Rite.t.citation_shapes}'s own doc comment for why
+ this field is rite-supplied at all.
- [creed], [gloria], [preface]: {!Rubrics_of}, IGMR n. 53/67-68/364-365.
[~lectionary] is a caller-supplied parameter, not a value closed over an