summaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef/rubrics_ef.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-22 13:38:27 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-22 13:38:27 +0200
commit41263d60432fadd2aef3f04de66b60561f89cbec (patch)
treec7fcffcdb2650ea8c98b07b75c03f69e632b4b4a /lib/rites/rite_ef/rubrics_ef.ml
parent3bfa0c459e3c0b5bfa962b7dbb0227db5a8ba09f (diff)
downloadcolitur-41263d60432fadd2aef3f04de66b60561f89cbec.tar.gz
colitur-41263d60432fadd2aef3f04de66b60561f89cbec.zip
fix(ef): RG 476(f) -- the Creed is not said at a Requiem Mass
colitur said the Creed IS said on All Souls' Day and every other Requiem-shaped day: RG 475(b)'s "in festis I classis" branch fired on rank alone, with nothing checking RG 476(f), "Non dicitur symbolum ... f) in Missis defunctorum". Allow-listed as L1 in expected-divergences-lms.sexp on the argument that [creed] has no notion of a Requiem Mass in its inputs and could not express the rule without a signature change. That argument does not hold. Colour.Black is used by exactly two celebrations in the whole engine, verified by grepping every occurrence in lib/ and data/: commemoration-of-all-souls (data/ef/sanctoral.sexp) and Good Friday (temporal_ef.ml, already false via the earlier RG 23(b) feria exclusion and has no Mass at all in the 1955-restored Holy Week). So on every day this engine can construct, colour = Black if and only if the Mass is a Requiem -- a citable implication (RG 117 assigns black to Masses of the dead) on this data, not a heuristic. Rite_ef.Rubrics_ef.creed now reads observed.colour as RG 476(f)'s own guard, positioned ahead of 475(b)'s rank branch. A new test, test_colour_black_population_is_exactly_two, sweeps both the shipped data and Temporal_ef's own code across a century and fails loudly the day a third Colour.Black celebration is ever introduced, so the proxy cannot silently rot. L1 is closed in expected-divergences-lms.sexp, citation preserved. Blast radius, measured (full 1583-9999 sweep, grouped by observed slug): 8 416 days change from true to false, every one commemoration-of-all-souls (missing from exactly 1 of the 8 417 domain years, a boundary-year transfer effect at 1583/9999). A further 8 416 Colour.Black days are Good Friday, unaffected (already false before this fix). colitur day/readings stay byte-identical to v0.10.1 (checked directly against a v0.10.1 worktree build, 9 domain-spanning years); colitur rubrics changes on exactly the 8 416 days above. colitur emit --format sexp's pretty-printed line count for 2027 moved 9010 -> 9011 as a side effect: Sexplib.Sexp.to_string_hum wraps by column width, and All Souls' Day 2027's record grew one wrapped line because "false" is one character longer than "true". Cosmetic only -- no field's data changed -- and pinned in test/cli.t with the measurement recorded.
Diffstat (limited to 'lib/rites/rite_ef/rubrics_ef.ml')
-rw-r--r--lib/rites/rite_ef/rubrics_ef.ml58
1 files changed, 52 insertions, 6 deletions
diff --git a/lib/rites/rite_ef/rubrics_ef.ml b/lib/rites/rite_ef/rubrics_ef.ml
index 6345399..ab9da32 100644
--- a/lib/rites/rite_ef/rubrics_ef.ml
+++ b/lib/rites/rite_ef/rubrics_ef.ml
@@ -26,12 +26,37 @@
engine resolves ONE observed office and ONE Mass per civil day (see
Rite.t.readings' own doc comment) -- it has no separate "which votive
Mass is said" dimension. So the "vel/et...votivis" halves of 475(a)/(b),
- 476(c) entirely, 476(d)'s "et votivis" half, and 476(f) (Requiem Masses,
- also not modelled) are genuinely inapplicable to this implementation --
- a documented scope limit, not a defect. 476(e) needs no branch at all:
- [creed] below reads only [observed], never a day's admitted
- commemorations, so a commemoration can never change its answer by
- construction. *)
+ 476(c) entirely, and 476(d)'s "et votivis" half are genuinely
+ inapplicable to this implementation -- a documented scope limit, not a
+ defect. 476(e) needs no branch at all: [creed] below reads only
+ [observed], never a day's admitted commemorations, so a commemoration
+ can never change its answer by construction.
+
+ 476(f) ("in Missis defunctorum") is DIFFERENT: this file used to carry
+ it in the same "not modelled" list above, on the reasoning that
+ [creed]'s inputs (temporal/observed/date) have no notion of "this Mass
+ is a Requiem". That reasoning was wrong, found by the LMS Ordo layer
+ (test_lms_ordo.ml, allow-list entry L1, now closed -- see
+ expected-divergences-lms.sexp) on 2025-11-03, All Souls' Day: colitur
+ said the Creed where the Ordo, correctly, does not. [observed] DOES
+ carry a usable signal -- RG 117 assigns black to Masses of the dead,
+ and {!Colour.Black} is used by exactly TWO celebrations in this whole
+ engine, verified by grepping every [colour Black]/[Colour.Black] site
+ in lib/ and data/: [commemoration-of-all-souls] in
+ data/ef/sanctoral.sexp, and Good Friday in temporal_ef.ml (which is a
+ Holy Week FERIA, RG 23(b), already excluded by the [n >= -6 && n <=
+ -1] branch below regardless of colour, and has no Mass at all in the
+ 1955-restored Holy Week). So on every day this engine can actually
+ construct, [colour = Black] if and only if the Mass is a Requiem --
+ a citable implication ON THIS DATA, not a heuristic guess. [creed]
+ below uses it as 476(f)'s own guard. This is a PROXY, not a general
+ "is this a Requiem Mass" field, and it is only as good as that
+ two-member population: {!test_rubrics_ef}'s own
+ [test_colour_black_population_is_exactly_two] fails loudly the day a
+ third [Colour.Black] celebration is added anywhere, so the proxy
+ cannot silently rot into covering (or missing) a non-Requiem black
+ Mass. If that ever happens, this guard needs re-deriving, not merely
+ re-approving. *)
open Colitur_kernel
@@ -223,6 +248,27 @@ let creed ~(temporal : (Vocab_ef.season, Vocab_ef.rank) Temporal.t)
Precedence_ef.is_vigil slug
then false
else if
+ (* RG 476(f): "in Missis defunctorum" -- the Creed is never said at a
+ Requiem Mass, checked here, ahead of 475(b)'s rank branch, the same
+ "category excludes regardless of rank" position as the feria and
+ vigil checks immediately above (All Souls' Day is [Class1], so
+ without this guard 475(b) would grant it [true] unopposed, which is
+ exactly the defect this guard fixes -- see this file's own header
+ for the two-member [Colour.Black] population this proxy rests on,
+ and {!Colour.Black}'s own citation, RG 117, for why colour is the
+ Requiem signal. Placed before, not after, 475(b)/(c)/(e) so a black
+ Class1 or Class2 day can never reach them; nothing above this point
+ (the Nativity/Easter/Pentecost octave override, the Sunday rule, the
+ feria and vigil exclusions) is ever reachable by a Requiem Mass on
+ the shipped data either -- a Requiem is never kept on a Sunday or
+ inside a privileged octave -- so this guard's own position relative
+ to THOSE branches is moot on real data, checked, not merely assumed:
+ {!creed_apostle_slugs} and [marian_slugs] contain no Black-coloured
+ entry, and 2 November can never fall inside any of the three
+ octaves 475(d) names. *)
+ observed.Celebration.colour = Colour.Black
+ then false
+ else if
(* RG 475(b): "in festis I classis". Genuine feasts only, by
construction of the two exclusions immediately above (feria I
classis -- Ash Wednesday and Holy Week, the only feriae that are