aboutsummaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-12 05:25:58 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-12 05:25:58 +0200
commit0121abf66700879b31ef0b9a13e936b95e123c8f (patch)
tree383e96e03596820ade6cf1744a9244575cab3083 /lib/rites/rite_ef
parentcb200a3f95e24f67c1d08b2ceb09404bf57a1636 (diff)
downloadcolitur-0121abf66700879b31ef0b9a13e936b95e123c8f.tar.gz
colitur-0121abf66700879b31ef0b9a13e936b95e123c8f.zip
kernel(precedence): fix round 1 -- RG23-26 govern ferial commemoration, not RG109
Review round 1 (F1, Critical): the commemoration-eligibility fix from the previous commit silently dropped II-class Advent and Lent Ember ferias when impeded, while ordinary (lower-solemnity) ferias of the same seasons kept their commemoration -- backwards on any reading. Reproduced: 1900-12-21 (an Advent Ember Friday) lost its commemoration entirely; 2026-12-21 (an ordinary Advent feria the same week) kept its. F2 (Important, the direct cause of F1): the branch's own justification mis-stated RG 109 as an exhaustive list of the only temporal circumstances that generate a commemoration. RG 109 is headed "Commemorationes privilegiatae sunt commemorationes" and closes "Omnes aliae commemorationes sunt commemorationes ordinariae" -- it sorts commemorations that already exist into two HONOUR classes (RG 108's differing liturgical hours), and says nothing about which offices have the right to be commemorated at all. That right belongs to Caput IV, "De feriis" (RG 21-27), never opened by the original pass: RG 24 (II-class ferias): "si vero impediuntur, commemorari debent" -- if impeded, MUST be commemorated. Not optional. RG 25 (III-class ferias): same mandate. RG 26: every feria not named in 23-25 is IV class, and IV-class ferias are NEVER commemorated -- the one exclusion RG 21-27 actually states. The omission branch is now gated on `rank = Class4` (RG 26) directly, not on `privilege_of = Ordinary` -- the old gate happened to reach the right answer for IV-class ferias (RG 26 also excludes them, for a reason the old citation did not give) and the wrong one for II/III- class Ember ferias RG 109(e) did not name by letter. RG 109(e) itself is also corrected: its bare "feriis Adventus, Quadragesimae et Passionis" previously excluded the Advent and Lent Ember sub-days by analogy with (d)'s separate September carve-out. RG 91's own TABLE needs an explicit "exceptis feriis Quatuor Temporum" at entries 22 and 25 to keep Ember days from being double- listed against their own entry 18 -- an exception that would be unnecessary drafting if "feriae Adventus"/"feriae Quadragesimae" did not already include their Ember sub-days by default. RG 109(e) carries no such exception, so it is read at that same default, inclusive scope: the Advent and Lent Ember ferias are privileged under (e), not merely ordinary-but-commemorable. (d)'s own existence is unaffected -- September Ember days sit outside Advent/Lent/Passiontide under any reading, so (d) remains necessary regardless. Verified: 1900-12-21 and 1902-02-22 now correctly commemorate their Ember ferias; 2026-12-21 and 1902-02-24 (ordinary ferias) unchanged. Blast radius re-measured against the prior commit, 1900-2100: 102 civil days changed, every one an Advent/Lent Ember (or Ember-vs- Joseph-collision) day regaining its commemoration, nothing else. Validate re-swept exhaustively, 1583-9998: 0 failures. F6: two privilege-boundary test rows that had been bent to expect the bug's own output (Commemorate -> Omit) are restored to what RG 24/25 actually require, now Commemorate(Privileged) given the RG 109(e) correction above -- these are the rows that should have caught F1. F7: admit_cases had no witness for RG 111(b)'s rank floor that wasn't already Class2, so reverting that filter only reddened the oracle suite, never this file. Added a row (II-class Sunday, sole candidate an ordinary Class3) that fails without the filter and passes with it. F9: RG 122 cited alongside RG 128(b) for Holy Thursday's white -- states the same fact affirmatively ("Demum adhibetur color albus, feria V Hebdomadae sanctae...") rather than as an exception to violet.
Diffstat (limited to 'lib/rites/rite_ef')
-rw-r--r--lib/rites/rite_ef/precedence_ef.ml204
-rw-r--r--lib/rites/rite_ef/temporal_ef.ml7
2 files changed, 136 insertions, 75 deletions
diff --git a/lib/rites/rite_ef/precedence_ef.ml b/lib/rites/rite_ef/precedence_ef.ml
index fd83383..88f1a54 100644
--- a/lib/rites/rite_ef/precedence_ef.ml
+++ b/lib/rites/rite_ef/precedence_ef.ml
@@ -380,22 +380,46 @@ let privilege_of (c : Vocab_ef.rank Precedence.candidate) : Precedence.privilege
(* (c) register line 375: "of days within the Octave of the Nativity". *)
else if is_temporal && String.starts_with ~prefix:nativity_octave_prefix slug then
Precedence.Privileged
- (* (d) register line 375-376: "of September Ember days" -- deliberately
- ONLY the September set: RG 109 does not list the Advent or Lent Ember
- sets (also II class, RG 91 entry 18), so those must fall through to
- "ordinary", not be caught here or at (e) below. *)
+ (* (d) register line 375-376: "of September Ember days" -- named on its
+ own because September falls entirely outside (e)'s three seasons
+ (Advent/Lent/Passiontide) under ANY reading, not because it needs
+ excluding FROM (e) the way review round 1's F1/F2 finding corrected
+ the Advent/Lent Ember sets below to no longer need. *)
else if is_temporal && String.starts_with ~prefix:september_ember_prefix slug then
Precedence.Privileged
(* (e) register line 376: "of ferias of Advent, Lent and Passiontide" --
- [not (is_ember_18 slug)] is required, not redundant with (d): the
- Advent and Lent Ember prefixes ("ef-advent-ember-", "ef-lent-ember-")
- also start with this branch's own [alp_feria_prefixes] entries
- ("ef-advent-", "ef-lent-"), and RG 109 does not privilege them (see (d)
- above) -- without this exclusion they would wrongly match here. *)
- else if is_temporal
- && (not (is_ember_18 slug))
- && List.exists (fun p -> String.starts_with ~prefix:p slug) alp_feria_prefixes
- then Precedence.Privileged
+ CORRECTED, fix round 1 (F1/F2): this branch previously excluded the
+ Advent and Lent Ember sets via [not (is_ember_18 slug)], reading RG
+ 109(e)'s bare "feriis Adventus, Quadragesimae" as tacitly narrower than
+ the ordinary ferias of those seasons, on the theory that (d)'s separate
+ September carve-out implied Ember days needed excluding from (e) too.
+ That reading does not survive comparing (e)'s text against RG 91's own
+ TABLE entries for the same seasons (register §4, "Ferias of Lent and
+ Passiontide... EXCEPTIS feriis Quatuor Temporum" at entry 22; "Ferias
+ of Advent... EXCEPTIS feriis Quatuor Temporum" at entry 25): the table
+ needs an explicit "exceptis" to keep Ember days from being double-
+ listed at both their own entry 18 AND entries 22/25 -- and an explicit
+ exception is only necessary because, ABSENT one, "feriae Adventus"/
+ "feriae Quadragesimae" already DO include their Ember sub-days by
+ default (an unnecessary exception is not how a rubrical text is
+ drafted). RG 109(e) carries no such "exceptis" clause, so its bare
+ "feriis Adventus, Quadragesimae" is read at that same default,
+ INCLUSIVE scope: the Advent and Lent Ember ferias ARE "ferias of
+ Advent"/"of Lent" in RG 109(e)'s sense, hence privileged, not merely
+ ordinary. (d)'s own separate existence is unaffected by this reading
+ either way -- September Ember days sit in "time after Pentecost",
+ never within Advent/Lent/Passiontide under any reading, so (d) remains
+ necessary regardless; it is not evidence for excluding Advent/Lent
+ Ember from (e), only for including September at all.) Consequently
+ [is_ember_18] is no longer tested here -- an Advent/Lent Ember slug
+ matches this branch exactly like an ordinary Advent/Lent feria slug
+ does, via the same [alp_feria_prefixes] prefix test; only a September
+ Ember slug is structurally excluded, because "ef-september-ember-*"
+ never starts with any of [alp_feria_prefixes] ("ef-advent-"/"ef-lent-"/
+ "ef-passiontide-") in the first place -- (d) above already privileges
+ it under its own name. *)
+ else if is_temporal && List.exists (fun p -> String.starts_with ~prefix:p slug) alp_feria_prefixes then
+ Precedence.Privileged
(* (f) register line 376-377: "of the Major Rogations, in Mass" -- the
Major Litanies (25 April, RG 80) are not yet computed anywhere in this
codebase (temporal_ef.ml's own comment on [temporal]'s Rogation branch:
@@ -469,73 +493,102 @@ let disposition ~(winner : Vocab_ef.rank Precedence.candidate)
else if
is_temporal
&& (not (is_vigil (Slug.to_string cel.Celebration.slug)))
- && (match privilege_of loser with Precedence.Ordinary -> true | Precedence.Privileged -> false)
+ && cel.Celebration.rank = Class4
then
- (* Task 16, primary-source-verified (RG 93, 95, 109, 113): an ordinary,
- NON-privileged TEMPORAL-cycle office has no standing to be
- commemorated at all when impeded -- it is simply omitted, not the
- "commemorated or omitted, per rubric" residual RG 95 leaves open for
- everything else. Three primary texts read together settle this:
+ (* CORRECTED, fix round 1 (F1/F2 -- both real, the second the direct
+ cause of the first): the branch this replaces gated on
+ [privilege_of loser = Ordinary], justified by treating RG 109 as an
+ "exhaustive, closed list of the only temporal-origin circumstances
+ that ever generate a commemoration". That justification does not
+ survive reading RG 109 itself: it is headed "Commemorationes
+ PRIVILEGIATAE sunt commemorationes" and closes "Omnes aliae
+ commemorationes sunt commemorationes ORDINARIAE" -- it sorts
+ commemorations that ALREADY exist into two HONOUR classes
+ (privileged vs ordinary, RG 108's differing liturgical hours), and
+ says nothing about which offices have the RIGHT to be commemorated
+ in the first place. Testing [privilege_of = Ordinary] as an
+ ELIGIBILITY gate therefore happened to reach the right answer for
+ IV-class ferias (they are never commemorated, but for a reason
+ RG 109 does not state) and the WRONG answer for II- and III-class
+ ferias impeded during a season RG 109(e) does not privilege by name
+ (Advent 17-23 Dec's own ordinary-non-Ember ferias were fine, already
+ matching (e)'s slug prefix; the Advent and Lent EMBER ferias were
+ not, since the pre-fix (e) excluded them -- see [privilege_of]'s own
+ fix-round-1 comment above, which independently corrects THAT half
+ too). Confirmed wrong by direct reproduction (fix-round-1 review):
+ 1900-12-21 (an Advent Ember Friday, RG 91 entry 18, II class) lost
+ its own commemoration entirely under the pre-fix code, while an
+ ORDINARY (non-Ember, lower-solemnity) Advent feria the same week
+ kept its commemoration -- backwards on any reading.
- - RG 95: "Alia festa, ab Officio gradus superioris accidentaliter
- impedita, AUT COMMEMORANTUR AUT, eo anno, PENITUS OMITTUNTUR, IUXTA
- RUBRICAS" -- impeded offices are "either commemorated or, that
- year, entirely omitted, ACCORDING TO THE RUBRICS" -- i.e. some
- OTHER rule decides which fate applies; RG 95 itself does not grant
- a commemoration to everything impeded.
- - RG 109 gives that other rule for the temporal cycle: an EXHAUSTIVE,
- closed six-item list of the only temporal-origin circumstances that
- ever generate a commemoration -- (a) of a Sunday; (b) of a I-class
- day; (c) of days within the Nativity Octave; (d) of the September
- Ember days; (e) of Advent/Lent/Passiontide ferias; (f) of the Major
- Rogations. [privilege_of] above already implements exactly this
- list (its own six branches, each cited to its own RG 109 letter);
- its terminal "[else Precedence.Ordinary]" is what a TEMPORAL-origin
- candidate falls through to when it matches NONE of (a)-(f) -- an
- ordinary green-season feria of Time after Epiphany/Pentecost/
- Easter, a plain (non-Ember) Advent/Lent weekday already caught by
- (e), or a Minor Rogation day (RG 87 -- deliberately NOT named by
- RG 109(f), see [privilege_of]'s own comment on that letter).
- - RG 113: "Commemoratio de Tempore fit primo loco" -- the
- commemoration OF THE TEMPORAL DAY is made FIRST [in the list, when
- one is due] -- presupposes RG 109 already answered whether one is
- due; it does not itself create a right for every impeded feria.
+ The actual rule is Caput IV, "De feriis" (RG 21-27), which the
+ original Task 16 pass never opened -- a FERIAL-CLASS-keyed rule,
+ entirely separate from RG 109's HONOUR-class one:
+ - RG 23 (I-class ferias -- Ash Wednesday, Holy Week): "nullam
+ admittunt commemorationem, nisi unam privilegiatam" -- admit no
+ commemoration except one privileged one. Never actually reaches
+ this function as a loser (these ferias structurally always
+ outrank anything that could coincide with their dates -- {!band}
+ entries 2/7, see that function's own file comment and the Task 11
+ Easter-window invariant), so this clause has no live witness, the
+ same as before.
+ - RG 24 (II-class ferias -- Advent 17-23 Dec, the Advent/Lent/
+ September Ember ferias, RG 91 entry 18): "si vero impediuntur,
+ COMMEMORARI DEBENT" -- if indeed impeded, they MUST be
+ commemorated. Not optional, not conditioned on RG 109's list.
+ - RG 25 (III-class ferias -- ordinary Lent/Passiontide ferias, RG 91
+ entry 22; ordinary Advent ferias to 16 Dec, entry 25): "Hae
+ feriae, si impediuntur, commemorari debent" -- same mandate.
+ - RG 26: "Omnes feriae, numeris 23-25 non nominatae, sunt feriae IV
+ classis; quae NUNQUAM COMMEMORANTUR" -- every feria not named in
+ 23-25 is IV class, and IV-class ferias are NEVER commemorated.
+ This is [ferial_rank]'s own unqualified IV-class catch-all
+ (temporal_ef.ml), covering the ordinary green-season ferias of
+ Time after Epiphany/Pentecost, Septuagesima, Paschaltide outside
+ its privileged octave, and the Minor Rogation days (RG 87/88 --
+ they change nothing in the Office, so they take their season's
+ plain ferial class, which for Paschaltide-adjacent dates is
+ IV, not a special one).
- So testing [privilege_of loser = Ordinary] here, for a TEMPORAL-origin
- loser specifically, is not a second, parallel "is this commemorable"
- predicate that could drift from RG 109's own list -- it IS RG 109's
- list, already computed by [privilege_of] for the commemoration this
- branch is about to deny. SANCTORAL losers are entirely unaffected
- (the [is_temporal] guard): RG 111(c)/(d) admit an "ordinary"
- commemoration of a losing SAINT freely, with no such closed-list
- gate -- this omission is specific to the temporal cycle's own
- ferial/Sunday-tail offices, never to a saint.
+ So this branch is now gated directly on RG 26's own condition
+ ([rank = Class4]), which is the ONLY ferial class RG 21-27 excludes
+ from commemoration -- Class1 is structurally unreachable here (RG
+ 23, above); Class2 and Class3 both fall through to the final
+ [Commemorate] branch below (RG 24/25's mandate), tagged with
+ whatever HONOUR class [privilege_of] separately computes for them
+ under RG 109 -- a question this branch no longer conflates with
+ eligibility. SANCTORAL losers are entirely unaffected (the
+ [is_temporal] guard): Caput IV governs FERIAE, RG 21's own opening
+ definition ("Nomine feriae intelleguntur singuli dies hebdomadae,
+ praeter dominicam"), never a saint's day; RG 111(c)/(d) admit an
+ "ordinary" commemoration of a losing SAINT freely, with no such
+ class-keyed gate.
Empirically confirmed against the missalemeum oracle (Task 16,
2026-2027, both years): every one of ~190 days where a saint's feast
- impedes an ordinary (non-privileged) temporal feria shows ZERO
- commemorations in the oracle, including the exact shape this fixes
- (e.g. "St. Marcellus I" impeding the plain "Friday after Epiphany",
- 6/730 identical instances of the pattern per week of ordinary time)
- -- and the SAME fix, for the same reason, independently corrects the
- Minor Rogation days (RG 87) losing to a saint (9/730 days), which
- [privilege_of]'s own (f) comment already flags as NOT RG 109(f).
+ impedes an ordinary (IV-class, non-privileged) temporal feria shows
+ ZERO commemorations in the oracle (e.g. "St. Marcellus I" impeding
+ the plain "Friday after Epiphany"), and the SAME rank-4 gate,
+ independently, correctly still omits the Minor Rogation days (RG 87)
+ losing to a saint -- both consequences of RG 26 alone now, not of a
+ reading of RG 109 that RG 109's own text does not support.
- [is_vigil] is EXCLUDED from this branch deliberately: a II/III-class
- vigil is temporal-origin too (when it is the Ascension/Pentecost-
- adjacent case {!of_temporal} produces) and [privilege_of] rightly
- calls it [Ordinary] (a vigil is none of RG 109(a)-(f)), but vigils
- are NOT governed by RG 109 at all -- they carry their OWN, separate,
- explicit commemoration mandate: RG 31 (II class) "Hae vigiliae
- praeferuntur diebus liturgicis III et IV classis; ET, SI
- IMPEDIUNTUR, COMMEMORANTUR, iuxta rubricas" and RG 32 (III class, St
- Lawrence) "si impeditur, COMMEMORATUR, iuxta rubricas" -- "if
- impeded, ARE/IS commemorated". So a vigil impeded WITHOUT triggering
- RG 33's full omission (the [is_omissible_vigil] branch above, e.g.
- impeded by an ordinary sanctoral feast that is neither a Sunday nor
- I class) must still fall through to the final [Commemorate] branch
- below, exactly like a sanctoral loser -- RG 31/32's own text, not
- RG 109's closed list, is what governs it. *)
+ [is_vigil] is EXCLUDED from this branch for the same reason as
+ before, restated under the corrected citation: a II/III-class vigil
+ is temporal-origin too (the Ascension/Pentecost-adjacent case
+ {!of_temporal} produces) and typically Class2, so it would already
+ fall through this branch's [rank = Class4] test harmlessly on its
+ own -- RG 91 has no IV-class vigil at all (this file's own entry-27/
+ 28 comments), so [is_vigil && rank = Class4] should never occur on
+ real data. Kept as an explicit, defensive guard (not load-bearing
+ for real data, but total over every candidate {!Precedence.resolve}
+ or {!Calendar} can construct, including shapes RG 91's table itself
+ does not describe) rather than relying on that absence silently: a
+ vigil, per RG 31 (II class, "si impediuntur, commemorantur") / RG 32
+ (III class, "si impeditur, commemoratur"), is ALWAYS commemorated
+ once RG 33 does not omit it outright, regardless of ferial class --
+ a rule Caput IV does not speak to at all (vigils are Caput V, RG
+ 28-34, not "feriae"). *)
Precedence.Omit
else
(* RG 95's other branch: "aut commemorantur aut penitus omittuntur" --
@@ -543,8 +596,9 @@ let disposition ~(winner : Vocab_ef.rank Precedence.candidate)
below I class (RG 111(c)/(d)'s "ordinary" commemoration, no closed
list the way the temporal branch above has), AND by an impeded
I-class Sunday (excluded from the [Transfer] branch above, and from
- the temporal-Ordinary [Omit] branch above because [privilege_of]'s
- (a) makes a Sunday loser [Privileged], never [Ordinary]): RG 109(a)
+ the temporal Class4 [Omit] branch above because a Sunday is never
+ IV class -- RG 11-12/91 entry 6/15 make every Sunday I or II class,
+ never a "feria" at all in Caput IV's own sense, RG 21): RG 109(a)
(register line 374) lists "of a Sunday" as a privileged commemoration
category, which presupposes an impeded Sunday stays put rather than
moving to another day the way a feast does -- [privilege_of] tags it
diff --git a/lib/rites/rite_ef/temporal_ef.ml b/lib/rites/rite_ef/temporal_ef.ml
index b39da79..1b3d219 100644
--- a/lib/rites/rite_ef/temporal_ef.ml
+++ b/lib/rites/rite_ef/temporal_ef.ml
@@ -426,6 +426,13 @@ let temporal d =
§3b's own RG126 note on the not-yet-modelled per-action
nuance), so this is a clean whole-day colour fact, not
a per-action one the day/colour model cannot express.
+ RG 122, fix round 1 (F9), states the same fact
+ affirmatively rather than as an exception to RG 128's
+ violet: "Demum adhibetur color albus, feria V
+ Hebdomadae sanctae, in Missa Chrismatis et in Missa in
+ Cena Domini" -- white is used, finally [among the
+ White section's own list], on Thursday of Holy Week,
+ in the Mass of Chrism and in the Mass in Cena Domini.
Task 16, found via the missalemeum oracle comparison:
every other Triduum day's oracle colour SET includes
violet as one option (Good Friday "bv", Holy Saturday