summaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-18 10:21:39 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-18 10:21:39 +0200
commite25558fee984837389d0e53cd6e17a3820f8e5ea (patch)
treeeea56c56f173e59fb8b4c0e68e251cdbf0166a22 /lib/rites/rite_ef
parentd8f4bece5480cfb94088fae62fa875a66b5b4e7e (diff)
downloadcolitur-e25558fee984837389d0e53cd6e17a3820f8e5ea.tar.gz
colitur-e25558fee984837389d0e53cd6e17a3820f8e5ea.zip
fix(ef): days within the Octave of the Nativity, and RG 69 for 29-31 Dec
M11 was the one entry in the missalemeum allow-list adjudicated against colitur, and it was right to be. The calendarium directs "Com. octavae Nativitatis" under each of 26, 27 and 28 December (LT.txt:5454-5459) and RG 109(c) makes a commemoration of the days within the Octave privileged. colitur emitted none. The cause was a reasoning error stated in Temporal_ef's own comment: "26-28 Dec are Stephen, John and the Innocents, hence sanctoral". Their office is sanctoral -- those II-class feasts win the day -- but they remain days WITHIN the Octave (RG 67, "Dies infra octavam sunt II classis"), and colitur built them as generic Class4 ferias. With no octave-day candidate there was nothing for the feast to be commemorated over. Building days 2-4 exactly as days 5-7 always were makes the commemoration fall out of the existing machinery rather than needing a special case: the feast wins on rank, the octave day loses, RG 109(c) privileges it, RG 111(c)'s single slot goes to it. A second, independent defect surfaced while fixing it. The octave-day branch covered 29-31 December unconditionally, so a Sunday falling there got a feria identity -- where RG 69 says a Sunday occurring 26-31 December SEMPER keeps its own office and commemorates the feast. Confirmed against the oracle rather than argued: missalemeum shows "Sunday in the Octave of Christmas" on 2035-12-30, a Sunday, where colitur showed a feria. Both named and anchors now exclude Sundays; anchors had asserted the octave slugs unconditionally and was wrong the same way. Blast radius, full sweep against the pre-change binary: 25251 days, every one 26-31 December, exactly two shapes, zero unclassified -- 21653 carrying an octave-day slug and 3598 that are all Sundays, the RG 69 correction. Allow-lists: M11 closed and removed. C6 narrowed 138 to 119, nineteen of its days having changed temporal identity rather than verdict. M15 widened 18 to 22 -- both streams now commemorate the octave, but the candidate is temporal-origin and carries no English name to match against missalemeum's own, this entry's documented limit on four more dates. Stated rather than glossed: this trades a substantive divergence, colitur omitting a commemoration the Missal directs, for a comparator limit, the commemoration existing but not being name-matchable. That is a real improvement, but what the oracle now proves is that both streams commemorate something on those days; the identity rests on the rubric and the calendarium. Register: section 6.17.
Diffstat (limited to 'lib/rites/rite_ef')
-rw-r--r--lib/rites/rite_ef/precedence_ef.ml36
-rw-r--r--lib/rites/rite_ef/temporal_ef.ml54
2 files changed, 80 insertions, 10 deletions
diff --git a/lib/rites/rite_ef/precedence_ef.ml b/lib/rites/rite_ef/precedence_ef.ml
index c9e6a55..dd75765 100644
--- a/lib/rites/rite_ef/precedence_ef.ml
+++ b/lib/rites/rite_ef/precedence_ef.ml
@@ -1325,9 +1325,39 @@ let disposition ~(winner : Vocab_ef.rank Precedence.candidate)
accurate, already decides every real case this codebase's current data
produces; the slug fallback below is exercised only between two
[Commemoration_only] candidates tied at {!unclassified} (138 of the 599,
- all order/count-invisible -- RG 91 has no table position for either of
- them to compare, so there is nothing more specific RG 113 could supply
- here either). {!band} needs a [context] this function itself does not
+ RG 91 having no table position for either of them to compare).
+
+ CORRECTED 2026-08-18: this used to add "all order/count-invisible", which
+ was true of 2005-2050 -- the range it was measured over -- and is NOT true
+ generally. 2038-06-02 is a live counter-example, found when the 2035/2038
+ oracle windows began comparing commemorations: the Ascension Vigil is II
+ class, RG 111(c) admits exactly ONE commemoration, and the two candidates
+ are `rogation-wednesday` and `sts-marcellinus-peter-erasmus` -- both
+ genuinely [Commemoration_only] (2 June reads "Commemoratio ... Comm." in
+ the calendarium itself, LT.txt:5148 and scan1.txt:2828, so the data is
+ right, not defective). The slug fallback therefore decides which
+ commemoration the day KEEPS, not merely how two kept ones are ordered.
+ missalemeum keeps the saints; this keeps the Rogation, on nothing but
+ "rogation-" sorting before "sts-".
+
+ AND THE RUBRIC GENUINELY DOES NOT SETTLE IT, checked rather than assumed.
+ RG 113's second sentence needs a table position and neither has one. Its
+ FIRST sentence, "Commemoratio de Tempore fit primo loco", looked like the
+ answer -- a Rogation being plausibly *de Tempore* -- but RG 81 forecloses
+ it in terms: "De Litaniis maioribus ... Earum autem commemoratio NON EST
+ HABENDA commemoratio «de Tempore»" (LT.txt:1399-1401), and RG 89 extends
+ RG 81 to the minor Litanies. So a Rogation commemoration is explicitly not
+ *de Tempore*, and tagging the entry [Subject.Temporal] to reach that
+ sentence would have been WRONG -- the [Subject.Saint] it carries,
+ inherited from the Major Litanies precedent, stands. RG 114 says only that
+ what exceeds the number is omitted, never which.
+
+ What remains is therefore a genuine LACUNA, not an unfound rule: the slug
+ order below is a documented CONVENTION for a case the Rubricae Generales
+ leave open, deliberately kept rather than changed to match the oracle --
+ which would be adopting an answer with no more warrant than this one, from
+ a source already adjudicated wrong six times over. See
+ docs/research/rules-register.md §6.16. {!band} needs a [context] this function itself does not
have (date/season/weekday) -- unlike [dignity], which read [rank] alone
-- so {!Precedence.resolve} now computes each candidate's own [band]
value once, generically, and hands it to [admit] as the trailing [int]
diff --git a/lib/rites/rite_ef/temporal_ef.ml b/lib/rites/rite_ef/temporal_ef.ml
index dacae9c..fa78cbe 100644
--- a/lib/rites/rite_ef/temporal_ef.ml
+++ b/lib/rites/rite_ef/temporal_ef.ml
@@ -276,9 +276,35 @@ let named d =
citations bootstrap, Plan 4, not the sanctoral one, Plan 3, which
already shipped in this branch). *)
Some (Advent, "ef-nativity-vigil", Colour.Violet, Class1)
- else if m = 12 && (dd = 29 || dd = 30 || dd = 31) then
- (* Days within the Octave of the Nativity; 26-28 Dec are Stephen, John and
- the Innocents, hence sanctoral (Plan 3). Colitur slugs -- lectionary gap. *)
+ else if m = 12 && dd >= 26 && dd <= 31 && Date.weekday d <> Date.Sun then
+ (* Days within the Octave of the Nativity, RG 67: "Dies infra octavam sunt
+ II classis". The octave runs 25 December to 1 January, so 26-31 are its
+ days 2-7.
+
+ CORRECTED 2026-08-18: this covered 29-31 ONLY, on the reasoning that
+ "26-28 Dec are Stephen, John and the Innocents, hence sanctoral". Their
+ OFFICE is sanctoral -- those three II-class feasts win the day -- but
+ they remain DAYS WITHIN THE OCTAVE, and the calendarium directs a
+ commemoration of the octave under each, verbatim (LT.txt:5454-5459):
+
+ 26 S. STEPHANI PROTOMARTYRIS, II classis. Com. octavae Nativitatis.
+ 27 S. IOANNIS AP. ET EV., II classis. Com. octavae Nativitatis.
+ 28 Ss. INNOCENTIUM Mm., II classis. Com. octavae Nativitatis.
+
+ Leaving 26-28 as generic Class4 ferias meant there was no octave-day
+ candidate for the feast to be commemorated OVER, so colitur emitted no
+ commemoration at all there -- the gap test_oracle.ml's own M11 records,
+ and the one entry in that file adjudicated against colitur rather than
+ the oracle. RG 109(c) makes "de diebus infra octavam Nativitatis
+ Domini" PRIVILEGED, so once the candidate exists RG 111(c)'s single
+ slot on a II-class day goes to it.
+
+ The Sunday guard is RG 69, not an implementation detail: "De dominica
+ infra octavam Nativitatis Domini, quae scilicet a die 26 ad 31
+ decembris occurrit, SEMPER fit Officium cum commemoratione festi forte
+ occurrentis" -- a Sunday falling 26-31 December keeps its OWN office
+ and commemorates the feast, the reverse of the other days. That Sunday
+ is built below; overriding it here would invert RG 69. *)
Some (Christmastide, Printf.sprintf "ef-nativity-octave-day-%d" (dd - 24), Colour.White, Class2)
else if m = 1 && dd = 1 then
(* RG 91 entry 5: 1 Jan is the Octave Day of the Nativity, the same table
@@ -1070,11 +1096,25 @@ let temporal d =
let anchors y =
let easter = Computus.gregorian_easter y in
let off n = Date.add_days easter n in
- [ ("ef-nativity", mk y 12 25);
+ (* Days within the Octave, 26-31 December, but ONLY those that are not
+ Sundays. RG 69 gives a Sunday occurring 26-31 December its OWN office
+ ("semper fit Officium cum commemoratione festi forte occurrentis"), so
+ in such a year that date carries the Sunday-within-the-octave slug, and
+ asserting an octave-day anchor there would assert the rubric's own
+ opposite. This list named 29/30/31 unconditionally until 2026-08-18 --
+ wrong whenever one fell on a Sunday, corrected alongside [named]'s own
+ Sunday guard and confirmed against the oracle, which shows "Sunday in
+ the Octave of Christmas" on 2035-12-30 where colitur used to show a
+ feria. 26-28 join for the first time: they are days within the octave
+ too (RG 67), which is what M11's missing commemoration turned on. *)
+ List.filter_map
+ (fun dd ->
+ let d = mk y 12 dd in
+ if Date.weekday d = Date.Sun then None
+ else Some (Printf.sprintf "ef-nativity-octave-day-%d" (dd - 24), d))
+ [ 26; 27; 28; 29; 30; 31 ]
+ @ [ ("ef-nativity", mk y 12 25);
("ef-nativity-vigil", mk y 12 24);
- ("ef-nativity-octave-day-5", mk y 12 29);
- ("ef-nativity-octave-day-6", mk y 12 30);
- ("ef-nativity-octave-day-7", mk y 12 31);
("ef-circumcision", mk y 1 1);
("ef-epiphany", mk y 1 6);
("ef-time-after-epiphany-sunday-1", holy_family_sunday y);