summaryrefslogtreecommitdiff
path: root/lib/rites
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-22 12:29:06 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-22 12:29:06 +0200
commit89b6cfbc8c2a9f5921c19543f893decc2497ef69 (patch)
tree50a95e596ab5adcc39f40b75af906c425504cda7 /lib/rites
parentd4682c13161b62bc83eaae37790493f670d39c01 (diff)
downloadcolitur-89b6cfbc8c2a9f5921c19543f893decc2497ef69.tar.gz
colitur-89b6cfbc8c2a9f5921c19543f893decc2497ef69.zip
fix(ef): check RG 24/25's ferial invariant instead of asserting it
rubrics_ef.ml's Creed check excluded feriae from 475(b)/(c)/(e) via an explicit test for feria I classis (Ash Wednesday, Holy Week) and vigils only. RG 24/25's feriae II and III classis (Advent 17-23 December, the Advent/Lent/September Ember sets, the numbered Lenten/Passiontide ferias) were excluded by no check at all, correct today only because of an unstated Temporal_ef property (no ferial-origin office it builds carries subject Lord/Bvm or an apostle-list slug). A comment read as if this were established "by construction of the two exclusions immediately above", which overclaimed: those two exclusions cover feria I classis only. Corrected the comments to name RG 24/25 explicitly, state what is and is not checked, and cite where the real guarantee comes from. Added a test that sweeps Temporal_ef.temporal across a century (1583-1682), asserting the invariant directly against every ferial-origin day found, with its own coverage counters confirming the span actually reaches Advent 17-23, all three non-Whitsun Ember sets, and Lenten/Passiontide ferias. The first run of the test found a real gap in its own population filter (RG 17(a)'s 2 January Holy Name fallback, a genuine feast sitting outside Temporal_ef.named for an architectural reason), fixed by naming that date explicitly rather than narrowing the span. Proved the test has teeth by mutation: forcing the ferial builder's default subject to Lord reddened it (and 24 other tests, expected collateral from an intentionally broad mutation) before being reverted. No production logic changed -- only comments in rubrics_ef.ml. day, readings and rubrics output confirmed byte-identical against the pre-fix binary for four spot years across the domain. Also corrects a stale test-case count in a prior task report (18 in the array, not the 19 recorded there); the array now genuinely holds 19.
Diffstat (limited to 'lib/rites')
-rw-r--r--lib/rites/rite_ef/rubrics_ef.ml70
1 files changed, 61 insertions, 9 deletions
diff --git a/lib/rites/rite_ef/rubrics_ef.ml b/lib/rites/rite_ef/rubrics_ef.ml
index eef86cb..6345399 100644
--- a/lib/rites/rite_ef/rubrics_ef.ml
+++ b/lib/rites/rite_ef/rubrics_ef.ml
@@ -160,7 +160,48 @@ let creed ~(temporal : (Vocab_ef.season, Vocab_ef.rank) Temporal.t)
liturgical action has no Mass in the 1955-restored Holy Week to
begin with, so the question is moot there independent of this
check -- but this structural test correctly excludes it too, since
- it is also named in RG 23(b).) *)
+ it is also named in RG 23(b).)
+
+ RG 24-25 (immediately following, same Caput IV) name TWO MORE
+ ferial classes this branch does not reach: feriae II classis (RG
+ 24 -- the Advent ferias 17-23 December, and the Quatuor Temporum
+ sets of Advent, Lent and September) and feriae III classis (RG 25
+ -- the numbered Lenten/Passiontide ferias from the Thursday after
+ Ash Wednesday to the Saturday before Passion Sunday II, and the
+ un-Embered Advent ferias to 16 December). NEITHER is excluded by a
+ check anywhere in this module -- this branch and RG 33's vigil
+ branch immediately below are the whole of what [creed] tests
+ before falling through to 475(b)/(c)/(e)'s own rank/subject/slug
+ guards. They do not need an explicit exclusion of their own for
+ 475(b): temporal_ef.ml's own [ferial_rank] never returns [Class1]
+ for them (only Ash Wednesday and Holy Week do, RG 23's own population,
+ already excluded above), so that branch is unreachable for them
+ regardless of anything checked here. But RG 24's own II-class set
+ DOES reach 475(c)'s [Class2] guard below, and 475(e)'s
+ apostle-slug guard carries no rank floor at all, so both classes
+ genuinely reach a live branch of this function. Getting [false]
+ there is NOT established by this exclusion, or by any check in
+ this file: it rests on an unstated property of {!Temporal_ef} --
+ every ferial-origin office it builds carries [subject = Temporal]
+ and an "ef-"-prefixed slug, never [Lord]/[Bvm] or a name on
+ {!creed_apostle_slugs}. Verified directly in temporal_ef.ml: the
+ Ember/Rogation/generic-ferial branches all go through [build]'s
+ own default [subject = Temporal], with exactly two documented
+ exceptions, neither able to reach a live branch below -- the
+ Sacred Triduum ([subject = Lord], but [Class1], already excluded
+ above) and the votive Office of the BVM on Saturday, RG 91 entry
+ 27 ([subject = Bvm], but [Class4], never satisfying 475(c)'s own
+ [Class2] guard).
+
+ (CORRECTED, review fix: this comment, and 475(b)'s own immediately
+ below, previously read as though "the two exclusions immediately
+ above" disposed of ferias in general -- they dispose of feria I
+ classis only. RG 24/25's own higher classes were excluded by NO
+ check, an unstated-invariant gap now named here rather than
+ silently relied on: test/test_rubrics_ef.ml's own ferial-invariant
+ sweep now asserts the Temporal_ef property above directly against
+ real output, so a future change that broke it would fail that
+ test rather than silently changing the Creed.) *)
n = -46 || (n >= -6 && n <= -1)
then false
else if
@@ -183,13 +224,17 @@ let creed ~(temporal : (Vocab_ef.season, Vocab_ef.rank) Temporal.t)
then false
else if
(* RG 475(b): "in festis I classis". Genuine feasts only, by
- construction of the two exclusions immediately above (feriae,
- vigils) -- every remaining [Class1] candidate reaching this branch
- is a real festum: the Nativity, Epiphany, Ascension, Corpus Christi,
- the Sacred Heart, Christ the King, a I-class sanctoral feast (the
- Assumption, the Immaculate Conception...), or a I-class Sunday
- (already [true] above via 475(a), so this branch is never the FIRST
- to grant those a [true], only ever redundant with it). *)
+ construction of the two exclusions immediately above (feria I
+ classis -- Ash Wednesday and Holy Week, the only feriae that are
+ ever [Class1]; RG 24/25's II- and III-class feriae are a different
+ population and never reach this rank at all, see the RG 23
+ comment's own note above -- and vigils) -- every remaining
+ [Class1] candidate reaching this branch is a real festum: the
+ Nativity, Epiphany, Ascension, Corpus Christi, the Sacred Heart,
+ Christ the King, a I-class sanctoral feast (the Assumption, the
+ Immaculate Conception...), or a I-class Sunday (already [true]
+ above via 475(a), so this branch is never the FIRST to grant those
+ a [true], only ever redundant with it). *)
observed.Celebration.rank = Vocab_ef.Class1
then true
else if
@@ -207,7 +252,14 @@ let creed ~(temporal : (Vocab_ef.season, Vocab_ef.rank) Temporal.t)
ships [subject = Saint] instead -- {!Precedence_ef.marian_slugs} is
the list built (and, here, reused rather than re-derived) precisely
because the [subject] field cannot be trusted alone for this
- question; see its own citation in precedence_ef.mli. *)
+ question; see its own citation in precedence_ef.mli.
+
+ This [Class2] guard is also the one live branch RG 24's own
+ II-class feriae (Advent 17-23, the Advent/Lent/September Ember
+ sets) genuinely reach -- the RG 23 comment above (this file, the
+ [n = -46 ...] branch) has the full account of why they still come
+ out [false] here: an unstated Temporal_ef property, checked by a
+ test, not a guard in this file. *)
observed.Celebration.rank = Vocab_ef.Class2
&& (observed.Celebration.subject = Subject.Lord
|| observed.Celebration.subject = Subject.Bvm