From 079e332e0a797105588787f7e5fdabd95ba1fa12 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 12 Aug 2026 04:12:41 +0200 Subject: kernel(precedence): three RG-verified EF precedence bugs, found via oracle Task 16's missalemeum oracle comparison (2026-2027) surfaced three distinct precedence-engine bugs, each confirmed against the primary 1962 Missale Romanum text and cross-checked against the oracle: 1. RG 33 (vigil omission) was transcribed backwards. The primary text reads "Vigilia II AUT III classis penitus omittitur" (a II OR III class vigil is entirely omitted on any Sunday or I-class feast) -- not "I aut II" as the register and this module's own rank check (Class1 || Class2) previously had it. I-class vigils (Nativity, Pentecost) can never actually lose in this engine (band always ranks them above anything that could coincide with their dates), so the Class1 half was dead code; the real bug was that Class3 (St Lawrence's vigil, the sole III-class vigil) was MISSING, so it fell through to an ordinary commemoration instead of RG 33's mandatory omission whenever 9 August landed on a Sunday. 2. RG 93/95/109/113 read together: an ordinary, non-privileged TEMPORAL-cycle office (a bog-standard green-season feria, a plain Advent/Lent Ember day, a Minor Rogation day) has no standing to be commemorated at all when impeded -- RG 109's six-item list is a CLOSED set of the only temporal circumstances that generate a commemoration, not a floor under which anything ordinary still gets one. The engine previously commemorated the losing feria itself in this situation; confirmed wrong against ~190 independent missalemeum days (2026-2027) showing zero commemorations for the exact shape. Vigils are explicitly excluded from this new rule -- RG 31/32 give them their own "if impeded, commemorated" mandate, independent of RG 109's list. 3. RG 111(b)'s Sunday admission slot is restricted to "de festo II classis" -- a rank restriction, not merely the best available ordinary candidate. A III/IV-class ordinary saint competing for a II-class Sunday's single commemoration slot had no such restriction applied before; confirmed wrong via St Hyginus (11 Jan, Class3) losing to Holy Family, which missalemeum shows entirely displaced, never commemorated. All three fixes are pure disposition/admission changes -- they never touch band, so the observed day (season/slug/rank/colour) is unaffected in every case; the lectio differential (which never compares commemorations) stays green untouched. test_precedence_ef.ml updated throughout: two previously-wrong test expectations corrected (the RG33 III-class-vigil boundary row, the IV-class-feria totality row), three privilege boundary rows sharpened from "commemorated but unprivileged" to "omitted entirely" now that temporal+ordinary means omission, and a new contrast row added to keep the SANCTORAL side of rule 2 covered separately from the TEMPORAL side. --- test/test_precedence_ef.ml | 93 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 17 deletions(-) (limited to 'test') diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml index aa98686..2f08864 100644 --- a/test/test_precedence_ef.ml +++ b/test/test_precedence_ef.ml @@ -375,17 +375,34 @@ let disposition_cases = of_temporal (off 38), "Omit" ); (* RG 33's own boundary, proved from both sides so the rule is shown to - gate on the WINNER too, not "any vigil is always omitted": *) + gate on the WINNER too, not "any vigil is always omitted": winner is + neither a Sunday nor I class, so RG 33's omission does not fire; the + vigil is temporal-origin ({!of_temporal}, the real Ascension Vigil) + and would otherwise land in Task 16's new "ordinary temporal loser -> + Omit" branch too (see the IV-class-feria row further down) -- this + row is what proves that branch's own [not (is_vigil ...)] guard: a + vigil, per RG 31's own text ("si impediuntur, commemorantur"), is + ALWAYS commemorated once RG 33 does not omit it outright, regardless + of RG 109's closed list. *) ( "RG33 boundary: vigil loses to an ordinary (non-Sunday, non-I-class) \ - II-class day -> Commemorate, NOT Omit", + II-class day -> Commemorate, NOT Omit (RG31's own vigil mandate)", cand ~origin:P.Sanctoral ~rank:V.Class2 ~layer:PE.universal_layer "ef-some-other-feast", of_temporal (off 38), "Commemorate(Ordinary)" ); - ( "RG33 boundary: a III-class vigil (outside RG33's I/II-class scope) \ - loses to a Sunday -> Commemorate, NOT Omit", + (* CORRECTED 2026-08-12 (Task 16, primary-source-verified): the register + previously (mis-)transcribed RG 33 as covering only I/II-class + vigils, so this row's own title used to read "outside RG33's + I/II-class scope" and expect Commemorate. The primary text ("Vigilia + II AUT III classis penitus omittitur...") covers II OR III class -- + St Lawrence's vigil (III class, RG 32) falling on ANY Sunday ("in + dominica quavis") is entirely omitted, exactly like a II-class vigil. + See {!PE.is_omissible_vigil}'s own comment for the full primary text + and the register correction. *) + ( "RG33 (corrected): a III-class vigil loses to a Sunday -> Omit, not \ + Commemorate", an_ordinary_sunday, cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:PE.universal_layer "ef-lawrence-vigil", - "Commemorate(Ordinary)" ); + "Omit" ); (* Task 11, issue (a): [disposition]'s own [is_vigil] check (the RG 33 omission test) is a SEPARATE call site from [band]'s -- both read the same private [is_vigil], but each needed its own witness, since a fix @@ -424,16 +441,45 @@ let disposition_cases = cand ~origin:P.Sanctoral ~status:Cel.Commemoration_only ~layer:PE.universal_layer "ef-suppressed-vigil", "Commemorate(Privileged)" ); - (* Totality: the lower ranks the RG 33/RG 95 branches never touch still - reach the RG 95 "commemorated or omitted" branch, not an - unhandled/exceptional case. *) + (* Totality (SANCTORAL side): the lower ranks the RG 33/RG 95/Task-16 + branches never touch still reach the RG 95 "commemorated or omitted" + branch's [Commemorate] side, not an unhandled/exceptional case -- RG + 111(c)/(d) admit an "ordinary" SAINT commemoration freely, with none + of RG 109's closed-list restriction the temporal branch below has. *) ( "III-class feast loses to a I-class day -> Commemorate", cand "ef-nativity", cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:PE.universal_layer "ef-some-saint-3", "Commemorate(Ordinary)" ); - ( "IV-class feria loses to a II-class Sunday -> Commemorate", + (* Task 16 (primary-source-verified: RG 95 + RG 109's closed list + RG + 113 -- see this branch's own comment in precedence_ef.ml for the full + three-text argument): an ORDINARY, non-privileged TEMPORAL-cycle + loser -- a bog-standard green-season feria of Time after Pentecost, + none of RG 109(a)-(f) -- has NO standing to be commemorated at all + when impeded; it is entirely omitted, not the "ordinary" + commemoration a losing SAINT would get (contrast the SANCTORAL row + immediately above, same rank, same kind of winner, opposite + [Commemorate]/[Omit] outcome -- the discriminating factor is + [origin], nothing else). Before this fix the engine wrongly + commemorated the losing feria itself here; confirmed wrong against + the missalemeum oracle (Task 16 report): every one of ~190 + structurally identical days (an ordinary sanctoral feast impeding an + ordinary temporal feria, 2026-2027) shows zero commemorations in an + independent published EF calendar. *) + ( "TASK16: an ORDINARY temporal feria loses to a II-class Sunday -> \ + Omit, not Commemorate (RG109's closed list; contrast the sanctoral \ + row above)", an_ordinary_sunday, cand ~rank:V.Class4 "ef-time-after-pentecost-1-sat", + "Omit" ); + (* Totality's other half: a SANCTORAL loser of the exact same rank as + the row above still reaches [Commemorate], proving the branch above + is gated on [origin] and not merely on rank -- without this row nothing + here would distinguish "temporal losers are omitted" from "IV-class + losers are omitted", which would be a much bigger (and wrong) claim. *) + ( "TASK16 contrast: a SANCTORAL IV-class loser still reaches \ + Commemorate(Ordinary)", + an_ordinary_sunday, + cand ~origin:P.Sanctoral ~rank:V.Class4 ~layer:PE.universal_layer "ef-some-minor-saint", "Commemorate(Ordinary)" ) ] @@ -506,29 +552,42 @@ let privilege_cases = already used by the entry-18 [band] row above. Both sourced from [Temporal_ef.temporal]. If [privilege_of] relied on the season prefix alone without excluding Ember slugs, both would wrongly come back - [Privileged] -- the exact trap this pair of rows guards against. *) + [Privileged] -- the exact trap this pair of rows guards against. + + CHANGED, Task 16: these used to expect [Commemorate(Ordinary)] -- + "not privileged" originally meant "commemorated, but without RG 109's + higher liturgical honours". Now that a TEMPORAL-origin [Ordinary] + loser is Task 16's own [Omit] branch (see precedence_ef.ml), "not + privileged" for a temporal candidate means "not commemorable at all" + -- a sharper, more direct assertion of the same underlying + [privilege_of] classification, via the one vantage point available + on that private function. *) ( "boundary: an Advent Ember day is NOT privileged (only September is, \ - RG109(d))", + RG109(d)) -- and being temporal+ordinary, TASK16 omits it entirely", cand "ef-nativity", of_temporal (mk 2026 12 16), - "Commemorate(Ordinary)" ); + "Omit" ); ( "boundary: a Lent Ember day is NOT privileged (only September is, \ - RG109(d))", + RG109(d)) -- and being temporal+ordinary, TASK16 omits it entirely", cand "ef-nativity", of_temporal (off (-39)), - "Commemorate(Ordinary)" ); + "Omit" ); (* Negative, RG 109(f)'s own boundary: the Minor Litanies/Rogations (Monday/Tuesday before Ascension, RG 87 -- [Temporal_ef.temporal] DOES compute these, unlike the Major Litanies RG 109(f) actually names, see [privilege_of]'s own comment) must NOT be mistaken for the Major Rogations RG 109(f) privileges: RG 88 says the Minor Rogations change nothing in the Office at all, so nothing about them is - privileged either. *) + privileged either -- and (Task 16) being temporal+ordinary, a Minor + Rogation day impeded by a saint is now omitted outright, matching the + missalemeum oracle exactly (Task 16 report: 11 May 2026 and 12 May + 2026, both Minor Rogation days impeded by a saint, show zero + commemoration of the Rogation in the independent oracle). *) ( "boundary: a Minor Rogation day is NOT privileged (RG109(f) names \ - the Major Litanies, not these)", + the Major Litanies, not these) -- TASK16 omits it entirely", cand "ef-nativity", of_temporal (off 36), - "Commemorate(Ordinary)" ) + "Omit" ) ] (* Task 9: [PE.admit] -- RG 111's admission counts (register line 378), -- cgit v1.3