From 60e87914718dd2c8e69bb89d8cc48d6bef9bfc74 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Sat, 22 Aug 2026 16:40:07 +0200 Subject: feat(ef): implement the calendarium's bissextile February shift The Missale Romanum's calendarium footnote for February (LT.txt:5011-5014, scan-corroborated scan2.txt:3050-3058): in a leap year the sixth kalends of March (24 February) is doubled rather than a 29th day appended, so St Matthias moves 24->25 February and St Gabriel of Our Lady of Sorrows 27->28, with 24 February itself carrying no fixed office that year. data/ef/expected-divergences-lms.sexp entry L3 tracked this as an open gap. Implemented as the rubric's own general mechanism (every fixed entry from 24 through 28 February shifts one civil day later in a leap year), not as "move these two named saints": the two readings are indistinguishable on shipped data (nothing else is fixed in that window) and diverge only for a future --overlay entry in the same range, which the mechanism reading covers correctly and a two-saints special case would not. This project has already been bitten once (RG 16(a)) by a rule implemented against shipped data's coincidental shape rather than the rubric itself. Kernel stays rite-agnostic: Rite.t gains a fixed_key field (Date.t -> (int * int) option), the same seam easter already establishes, read only by Layer.on_date's FIXED half -- the movable half (Easter_offset/Nth_weekday) is untouched. Default is the identity mapping, an optional argument on on_date, so every existing caller and every rite that supplies nothing is byte-identical to before this field existed. Date.is_leap is exposed in date.mli (already existed in date.ml) so the rite reads the kernel's own single-sourced leap-year definition. The EF implementation lives in Rite_ef.Temporal_ef.bissextile_fixed_key, fully cited, wired into Rite_ef.context. Blast radius, measured over the full 1583-9999 domain (Calendar.year run twice per civil year, real fixed_key vs identity, every day diffed): all 2,041 leap years in the domain show a visible change for each saint; 6,983 individual liturgical days change total, zero unclassified, across four shapes (Matthias vacates 24 Feb in 1,803 years / occupies 25 Feb in 1,811; Gabriel vacates 27 Feb in 1,699 / occupies 28 Feb in 1,670). L3's own prior estimate (1,650 years, observed-outright only) is confirmed close on the same definition (1,677 measured); the broader observed-or- commemorated count is higher, not lower, showing the narrow estimate undercounted visible impact rather than overcounting it. The lectio differential (2005-2050 fixture) gains a new cited entry, C40 in data/ef/expected-divergences.sexp: lectio implements no such shift, so every leap year in its window now diverges on the two shifted days (21 rows, not the naive 44 -- the comparator never compares commemorations, so a side where the shifted saint has zero comparator-visible footprint on both engines produces no row). The LMS Ordo's 2023-2024 fixture -- the window L3 was originally found in -- now matches on the Creed comparison; its formulary-override bucket count is corrected 182->181 (24 February leaves the counted Proper population, becoming Own_slug-sourced). The missalemeum oracle fixtures (2026-2027, 2038, 2035) cover no leap year and are unaffected. L3 is closed: converted from an active allow-list record to a prose closure paragraph (L1's own precedent), citation preserved verbatim, fix and measured blast radius recorded. The id-list assertion narrows to [L4] alone, and the now-dead "2024-02-24" -> "L3" date mapping is removed. Six golden values pinned across four new test cases: Matthias in a leap year (both the vacated and occupied sides) and a common-year control; Gabriel likewise, deliberately choosing a leap year where he is admitted only as an ordinary commemoration rather than winning outright, a different shape from Matthias's. Mutation-tested: forcing fixed_key back to identity reddens exactly five test cases -- the differential's Layer C count-pin (C40 drops to 0 actual vs 21 expected), the LMS Ordo's Creed and formulary-bucket checks, and both new golden pins -- confirming the tests actually exercise the fix. Reverted; dune test, the exhaustive sweep, and make check are all green. --- test/test_golden.ml | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'test/test_golden.ml') diff --git a/test/test_golden.ml b/test/test_golden.ml index ba25d8a..d680720 100644 --- a/test/test_golden.ml +++ b/test/test_golden.ml @@ -1315,6 +1315,67 @@ let test_rogation_wednesday_yields_to_a_feast_2026 () = "2026-05-13 wednesday season=paschaltide week=6 slug=ef-ascension-vigil rank=class-2 colour=white \ subject=temporal name_la=- comms=[robert-bellarmine:ordinary] in=- out=[]" +(* ---- The bissextile (leap-year) calendarium footnote, bissextile-shift + task, 2026-08-22 ---- + + The Missale Romanum's own CALENDARIUM table, February, footnote + (docs/research/LT.txt:5011-5014, scan-corroborated docs/research/ + scan2.txt:3050-3058): "In anno bissextili mensis februarius est dierum + 29, et festum S. Matthiae celebratur die 25 februarii, ac festum S. + Gabrielis a Virgine perdolente 28 februarii, et bis dicitur sexto + calendas, id est die 24 et die 25" -- in a leap year the sixth kalends + of March (24 February) is doubled rather than a 29th day appended, so + St Matthias (ordinarily 24 February) is kept on 25 February and St + Gabriel of Our Lady of Sorrows (ordinarily 27 February) on 28 February; + 24 February itself carries no fixed office that year. + {!Rite_ef.Temporal_ef.bissextile_fixed_key} implements this as the + rubric's own general MECHANISM, so a leap year moves the VACATED date's + slug/rank/colour away and the OCCUPIED date's toward it -- both sides + pinned for each saint, plus one common-year control apiece proving the + identity default is unchanged where the footnote does not apply. *) + +(* Matthias, 2044 (leap): 24 February carries no fixed office at all + (Class4 temporal only, zero commemorations); Matthias (Class2, an + Apostle) wins 25 February outright against that day's own Class4 + feria. *) +let test_bissextile_matthias_leap_2044 () = + check ~msg:"leap year: 24 February carries no fixed office, Matthias has moved away" 2044 2 24 + "2044-02-24 wednesday season=septuagesima week=2 slug=ef-septuagesima-2-wednesday rank=class-4 colour=violet \ + subject=temporal name_la=- comms=[] in=- out=[]"; + check ~msg:"leap year: Matthias observed outright on 25 February, not 24" 2044 2 25 + "2044-02-25 thursday season=septuagesima week=2 slug=matthias rank=class-2 colour=red subject=saint name_la=- \ + comms=[] in=- out=[]" + +(* Matthias, 2025 (common): unaffected control -- the identity default + applies, Matthias stays at his ordinary 24 February. *) +let test_bissextile_matthias_common_2025 () = + check ~msg:"common year: Matthias unaffected, still 24 February" 2025 2 24 + "2025-02-24 monday season=septuagesima week=2 slug=matthias rank=class-2 colour=red subject=saint name_la=- \ + comms=[] in=- out=[]" + +(* Gabriel of Our Lady of Sorrows, 2008 (leap): 27 February carries no + trace of him at all (not even a commemoration -- fixed_key removes him + from the candidate set entirely, RG 111's admission machinery never + sees him); on 28 February he is admitted as an ORDINARY commemoration + (Class3 ties the day's own privileged Lenten feria, which keeps + observed). A different shape from Matthias's outright win above, + deliberately pinned: the mechanism moves WHERE the saint is tried, not + whether he wins once he gets there. *) +let test_bissextile_gabriel_leap_2008 () = + check ~msg:"leap year: 27 February carries no trace of Gabriel, he has moved away" 2008 2 27 + "2008-02-27 wednesday season=lent week=3 slug=ef-lent-3-wednesday rank=class-3 colour=violet subject=temporal \ + name_la=- comms=[] in=- out=[]"; + check ~msg:"leap year: Gabriel admitted as an ordinary commemoration on 28 February, not 27" 2008 2 28 + "2008-02-28 thursday season=lent week=3 slug=ef-lent-3-thursday rank=class-3 colour=violet subject=temporal \ + name_la=- comms=[gabriel-of-our-lady-of-sorrows:ordinary] in=- out=[]" + +(* Gabriel of Our Lady of Sorrows, 2025 (common): unaffected control -- + observed outright at his ordinary 27 February. *) +let test_bissextile_gabriel_common_2025 () = + check ~msg:"common year: Gabriel unaffected, still observed on 27 February" 2025 2 27 + "2025-02-27 thursday season=septuagesima week=2 slug=gabriel-of-our-lady-of-sorrows rank=class-3 colour=white \ + subject=saint name_la=- comms=[] in=- out=[]" + (* RG 128, transcribed in docs/research/rules-register.md §3b: violet is used for "II/III-class vigils outside Paschaltide". Two of colitur's five vigils disagreed with that rule until the ef-oconnell-rubrics branch -- the @@ -1510,5 +1571,13 @@ let suite = Alcotest.test_case "RG87: Rogation Wednesday admitted (2024)" `Quick test_rogation_wednesday_admitted_2024; Alcotest.test_case "RG87/113: Rogation Wednesday yields to an impeded feast (2026)" `Quick - test_rogation_wednesday_yields_to_a_feast_2026 + test_rogation_wednesday_yields_to_a_feast_2026; + Alcotest.test_case "bissextile footnote: Matthias moves 24->25 February (leap, 2044)" `Quick + test_bissextile_matthias_leap_2044; + Alcotest.test_case "bissextile footnote: Matthias unaffected (common, 2025)" `Quick + test_bissextile_matthias_common_2025; + Alcotest.test_case "bissextile footnote: Gabriel of Our Lady of Sorrows moves 27->28 February (leap, 2008)" + `Quick test_bissextile_gabriel_leap_2008; + Alcotest.test_case "bissextile footnote: Gabriel of Our Lady of Sorrows unaffected (common, 2025)" `Quick + test_bissextile_gabriel_common_2025 ] ) -- cgit v1.3 From cd3e03bf3e5b040786838fc3c5639d7c29e9b3b8 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Sat, 22 Aug 2026 20:15:56 +0200 Subject: fix(ef): Rogation Monday/Tuesday are white, not violet (RG 119) Temporal_ef.temporal's Rogation Monday/Tuesday branch hardcoded Colour.Violet with no citation (data/ef/expected-divergences-lms.sexp's L6, surfaced by the LMS Ordo). RG 119 assigns white to the de-Tempore Office and Mass from the Paschal Vigil Mass to the Pentecost Vigil Mass exclusive; Easter+36/+37 sit inside that window. RG 128's own exhaustive four-case violet list never names Rogation days, and its vigil clause (d) is doubly inapplicable: these are not vigils, and they are inside Paschaltide, not outside it. RG 88 explains the violet actually seen in print sources: "de Litaniis minoribus nihil fit in Officio, sed tantum in Missa" -- the violet belongs to the Rogation Mass/procession, a distinct votive text this engine does not model, not to the day's own Office. Witnessed directly: LMS Ordo 2023-2024, 2024-05-06, "FERIA IV Cl W" with "Gl", the Office and Mass printed separately from the optional violet votive Mass of the Rogations. Cascade verified, not assumed: RG 432(b) omits the Gloria on every violet Mass, so the wrong colour was also silencing the Gloria on these two weekdays even though RG 237(e) (Breviary, ordinary Paschaltide ferias say Te Deum) already made it true underneath. White removes the 432(b) block, and the Gloria now follows Te Deum via 431(a), matching the Ordo's own "Gl" -- confirmed with dedicated golden pins in both test_golden.ml (colour) and test_rubrics_ef.ml (the Gloria flip), 2028-05-22/23 (neither day impeded that year). Closed L6 in data/ef/expected-divergences-lms.sexp. Reopened C8 in data/ef/expected-divergences.sexp (26 of 16801 rows, 2005-2050): lectio independently computes these two days violet too, so the two engines used to agree by sharing the same uncited assumption; colitur's colour is now correct and lectio's is not, so the comparator disagrees again, for the opposite reason. While reopening C8, found and corrected a genuine misattribution in its own prior closure note, which claimed lectio's violet was "RG 128(d)" -- 128(d) governs vigils outside Paschaltide and has nothing to do with Rogation days. Checked docs/research/rules-register.md for the same claim: not present there, but a related conflation was found and corrected at its O'Connell section 4(d) note, which had used a Rogation MASS/procession citation to "confirm" the day's own OFFICE colour. Blast radius measured in-process across the full 1583-9999 domain (throwaway probe, not committed): 4722 days total (2368 Rogation Mondays + 2354 Rogation Tuesdays actually observed outright, i.e. not impeded by a stronger sanctoral feast that year), all Violet->White, all with the Gloria flipping false->true alongside, zero anomalies. Mutation-tested: reverting the branch to Colour.Violet reddens 16 tests across Rubrics_ef, the lectio differential, the LMS Ordo suite and both golden pin files; restored and reconfirmed green (680 tests). --- data/ef/expected-divergences.sexp | 20 +++++++++------ lib/rites/rite_ef/temporal_ef.ml | 28 +++++++++++++++++++-- test/golden/grid-2027.html | 2 +- test/golden/grid-2027.tex | 2 +- test/golden/grid-2027.typ | 2 +- test/golden/ordo-2027.adoc | 2 +- test/golden/ordo-2027.html | 4 +-- test/golden/ordo-2027.md | 2 +- test/golden/ordo-2027.ms | 2 +- test/golden/ordo-2027.tex | 4 +-- test/golden/ordo-2027.txt | 2 +- test/golden/ordo-2027.typ | 4 +-- test/test_golden.ml | 32 ++++++++++++++++++++++++ test/test_lms_ordo.ml | 52 +++++++++++++++++++++++---------------- test/test_rubrics_ef.ml | 20 +++++++++++++++ 15 files changed, 135 insertions(+), 43 deletions(-) (limited to 'test/test_golden.ml') diff --git a/data/ef/expected-divergences.sexp b/data/ef/expected-divergences.sexp index 632854c..f98409b 100644 --- a/data/ef/expected-divergences.sexp +++ b/data/ef/expected-divergences.sexp @@ -131,13 +131,19 @@ Diff shapes: most rows carry [Slug_f; Rank; Colour_f; First_f; Gospel_f] (the te BLAST RADIUS, MEASURED, full 1583-9999 domain (not merely this fixture's 2005-2050 window): 6 983 liturgical days change, zero unclassified, across all 2 041 leap years in the domain -- see data/ef/expected-divergences-lms.sexp's own now-closed L3 entry for the full figures (this entry's own 21-row 2005-2050 population is the expected subset of that domain-wide count landing inside the fixture's own window: 11 leap years x up to 2 new rows each, minus the three already-explained overlaps above).") (expected_rows 21)) - ; C8 -- CLOSED, REMOVED (2026-08-18): 0 of 16801 rows, was 26. lectio builds - ; Rogation Monday and Tuesday now (RG 87, Easter+36/+37, violet under - ; RG 128(d)). The Wednesday is NOT built there and deliberately so: Easter+38 - ; is the Ascension's Vigil, which wins the day, and the rubric asks for a - ; commemoration -- a channel lectio's one-office-per-day temporal function - ; does not have. That is the same reason this entry never covered the - ; Wednesday either. Citation preserved in the register. + ((id C8) + (citation "RG 119 (Caput XVIII, \"De Colore Paramentorum\"): white is used \"in Officio et Missa de Tempore ... a Missa Vigiliae paschalis usque ad Missam vigiliae Pentecostes exclusive\" -- the de-Tempore Office and Mass are white from the Paschal Vigil Mass until the Pentecost Vigil Mass exclusive, and Rogation Monday/Tuesday (Easter+36/+37) sit inside that window. RG 128's own exhaustive four-case list for violet (Advent I-Christmas Eve; Septuagesima-Paschal Vigil; the September Ember ferias; vigils of II/III class OUTSIDE Paschaltide) never names Rogation days. RG 88 (\"de Litaniis minoribus nihil fit in Officio, sed tantum in Missa\"): the violet belongs to the Rogation MASS/procession, a distinct votive text this engine does not model, not to the day's own Office. Fixed in Rite_ef.Temporal_ef.temporal's Rogation branch, celebrant-rubrics-phase1 Bug 1, 2026-08-22 -- see that branch's own citation and data/ef/expected-divergences-lms.sexp's now-closed L6 entry, which is what surfaced it (LMS Ordo 2023-2024, 2024-05-06, \"FERIA IV Cl W\").") + (verdict colitur) + (note "REOPENED (2026-08-22, celebrant-rubrics-phase1, Bug 1 fix). Previously CLOSED, REMOVED (2026-08-18): 0 of 16801 rows, was 26, with this note, PRESERVED VERBATIM because it contains a misattribution now corrected rather than silently dropped: \"lectio builds Rogation Monday and Tuesday now (RG 87, Easter+36/+37, violet under RG 128(d)). The Wednesday is NOT built there and deliberately so: Easter+38 is the Ascension's Vigil, which wins the day, and the rubric asks for a commemoration -- a channel lectio's one-office-per-day temporal function does not have. That is the same reason this entry never covered the Wednesday either. Citation preserved in the register.\" + +THE MISATTRIBUTION: \"violet under RG 128(d)\" is wrong. RG 128(d) governs vigils of II/III class OUTSIDE Paschaltide; Rogation Monday/Tuesday are neither vigils nor outside Paschaltide. Checked against docs/research/rules-register.md (gitignored, local) while researching Bug 1: no claim of an RG 128(d) basis for Rogation colour exists there -- the misattribution was confined to this file's own closure note. It traces to Rite_ef.Temporal_ef.temporal's own Rogation branch, which hardcoded [Colour.Violet] with NO citation at all before this fix; whoever wrote this entry's closure note in 2026-08-18 apparently backfilled a plausible-looking but wrong citation for behaviour that was never actually cited in the code it described. + +WHY THIS REOPENS RATHER THAN STAYS CLOSED: the entry closed in 2026-08-18 because lectio, independently, ALSO computes these two days violet -- not because either engine's violet was ever verified against the Missal. Both engines shared the same uncited assumption, so the comparator saw agreement and the entry went to zero. Bug 1 corrected COLITUR's side to white (RG 119); lectio's own violet is unchanged (a sibling project, out of this repo, not modified here). The comparator now disagrees again, on the same 26 rows, for the OPPOSITE reason: previously colitur was wrong and lectio was wrong the same way; now colitur is right and lectio still carries the old, uncited assumption forward -- consistent with CLAUDE.md's own \"colitur vs missalemeum\" base-rate note for a different lineage, applied here to lectio directly: a fresh divergence is not presumptively colitur's fault once colitur has just been corrected FROM the shared error. + +MEASURED (test_differential.ml's own [classify], 2005-2050 fixture, DEBUGC8 probe run and reverted): exactly 26 rows, all with diffs=[Colour_f] alone -- season and slug already agree (lectio's own [easter]/colitur's [paschaltide] season labels are Layer A vocabulary synonyms, not a diff), and on every row lectio=violet, colitur=white. Dates: 2005-05-03, 2006-05-22/23, 2007-05-14, 2011-05-30, 2012-05-14, 2013-05-06, 2016-05-03, 2017-05-22/23, 2018-05-08, 2022-05-23/24, 2024-05-06, 2027-05-03, 2028-05-22/23, 2029-05-08, 2032-05-03, 2033-05-23/24, 2040-05-08, 2044-05-23/24, 2047-05-21, 2049-05-24. Fewer than the 2-per-year x 23-year x ~2 ceiling because a competing sanctoral feast impedes the Rogation office outright in some years on one or both of the two days (unchanged by this fix, gated on colitur's own [rogation-monday]/[rogation-tuesday] slug in [layer_c_reason] the same as before). The Wednesday remains absent from this entry for the same reason the pre-2026-08-18 and post-2026-08-18 notes both already gave: Easter+38 is the Ascension Vigil (RG 91 entry 21), which outranks the Rogation Wednesday commemoration outright on colitur's side, and lectio has no Rogation-Wednesday concept at all to compare against regardless. + +Gated on [(String.equal c.slug \"ef-rogation-monday\" || String.equal c.slug \"ef-rogation-tuesday\") && subset diffs [ Season; Slug_f; Colour_f ]] in [layer_c_reason] -- unchanged code, present since before this entry's 2026-08-18 closure and never removed; only the sexp record was removed when the count hit zero, per this file's own \"closed = 0 rows, not code deleted\" convention.") + (expected_rows 26)) ; C14 -- CLOSED, REMOVED (2026-08-18): 0 of 16801 rows, was 3. lectio has ; adopted RG 96(a)/97/98. Its transferIfImpededEF resolved each impeded ; I-class feast independently, so in 2008, 2035 and 2046 St Joseph and the diff --git a/lib/rites/rite_ef/temporal_ef.ml b/lib/rites/rite_ef/temporal_ef.ml index 1c916f4..fe08b2e 100644 --- a/lib/rites/rite_ef/temporal_ef.ml +++ b/lib/rites/rite_ef/temporal_ef.ml @@ -823,12 +823,36 @@ let temporal d = "ef-rogation-monday"/"-tuesday" are colitur-only keys and a lectionary gap for Plan 4 (CORRECTED, final fix wave, item 7 -- the lectionary bootstrap is Plan 4, not Plan 3), like the Ember - and Nativity-vigil keys above. *) + and Nativity-vigil keys above. + + COLOUR (L6, data/ef/expected-divergences-lms.sexp, CLOSED by this + fix): this branch used to hardcode [Colour.Violet] with no + citation at all. RG 119 (Caput XVIII, "De Colore Paramentorum"): + white is used "in Officio et Missa de Tempore ... a Missa Vigiliae + paschalis usque ad Missam vigiliae Pentecostes exclusive" -- the + de-Tempore Office AND Mass are white from the Paschal Vigil Mass + until the Pentecost Vigil Mass exclusive, and days 36/37 (Rogation + Monday/Tuesday) sit squarely inside that window. RG 128's own + exhaustive four-case list for violet (Advent I-Christmas Eve; + Septuagesima-Paschal Vigil; the September Ember ferias; vigils of + II/III class OUTSIDE Paschaltide) names Rogation days nowhere, and + its vigil clause is inapplicable twice over -- these are not + vigils, and they ARE inside Paschaltide. RG 88 ("de Litaniis + minoribus nihil fit in Officio, sed tantum in Missa") is why: the + violet belongs to the ROGATION MASS/procession alone, a distinct + votive text this engine does not model as a separate Mass (the + same per-action colour nuance temporal_ef.ml's own RG 126/RG 128 + Good-Friday-Communion citations already flag as unmodelled + elsewhere) -- the day's own OFFICE, which is what [colour] here + expresses, stays [season_colour s] like any other Paschaltide + feria. Witnessed directly: LMS 2023-2024, 2024-05-06 (Rogation + Monday), "FERIA IV Cl W" (white), "Mass of 5th Sunday after + Easter". *) let rogation = days_between easter d in if rogation = 36 || rogation = 37 then build ~season:s ~slug:(if rogation = 36 then "ef-rogation-monday" else "ef-rogation-tuesday") - ~colour:Colour.Violet ~rank:(ferial_rank d s) ~week:(week d) () + ~colour:(season_colour s) ~rank:(ferial_rank d s) ~week:(week d) () else match ember d with | Some (slug, rank, colour) -> build ~season:s ~slug ~colour ~rank ~week:(week d) () diff --git a/test/golden/grid-2027.html b/test/golden/grid-2027.html index daa6ba5..6741ad7 100644 --- a/test/golden/grid-2027.html +++ b/test/golden/grid-2027.html @@ -131,7 +131,7 @@ 1St. Joseph the WorkmanCol 3:14-15, 17, 23-24 · Matt 13:54-58 - 25th Sunday after EasterJas 1:22-27 · John 16:23-303Rogation MondayJas 1:22-27 · John 16:23-304St. Monica1 Tim 5:3-10 · Luke 7:11-165Vigil of the AscensionEph 4:7-13 · John 17:1-116The Ascension of Our LordActs 1:1-11 · Mark 16:14-207St. StanislausWis 5:1-5 · John 15:1-78Our Lady's Saturday OfficeEcclus 24:14-16 · John 19:25-27 + 25th Sunday after EasterJas 1:22-27 · John 16:23-303Rogation MondayJas 1:22-27 · John 16:23-304St. Monica1 Tim 5:3-10 · Luke 7:11-165Vigil of the AscensionEph 4:7-13 · John 17:1-116The Ascension of Our LordActs 1:1-11 · Mark 16:14-207St. StanislausWis 5:1-5 · John 15:1-78Our Lady's Saturday OfficeEcclus 24:14-16 · John 19:25-27 9Sunday after the Ascension1 Pet 4:7-11 · John 15:26-27; 16:1-410St. AntoninusEcclus 44:16-27; 45:3-20 · Matt 25:14-2311Sts. Philip & JamesWis 5:1-5 · John 14:1-1312Sts. Nereus, Achilleus, Domitilla, & PancrasWis 5:1-5 · John 4:46-5313St. Robert BellarmineWis 7:7-14 · Matt 5:13-1914Friday of the 7th Week of Eastertide1 Pet 4:7-11 · John 15:26-27; 16:1-415Vigil of PentecostActs 19:1-8 · John 14:15-21 diff --git a/test/golden/grid-2027.tex b/test/golden/grid-2027.tex index 674b9c4..d81bdb4 100644 --- a/test/golden/grid-2027.tex +++ b/test/golden/grid-2027.tex @@ -151,7 +151,7 @@ \begin{tabular}{|*{7}{p{\cellw}|}}\hline \textbf{ Sunday } & \textbf{ Monday } & \textbf{ Tuesday } & \textbf{ Wednesday } & \textbf{ Thursday } & \textbf{ Friday } & \textbf{ Saturday } \\ \hline & & & & & & \cellcolor{cwhite}\daycell{ 1 }{ St. Joseph the Workman }{ 1st Class }{ Col 3:14-15, 17, 23-24\ \textperiodcentered\ Matt 13:54-58 } \\ \hline -\cellcolor{cwhite}\daycell{ 2 }{ 5th Sunday after Easter }{ 2nd Class }{ Jas 1:22-27\ \textperiodcentered\ John 16:23-30 } & \cellcolor{cviolet}\daycell{ 3 }{ Rogation Monday }{ 4th Class }{ Jas 1:22-27\ \textperiodcentered\ John 16:23-30 } & \cellcolor{cwhite}\daycell{ 4 }{ St. Monica }{ 3rd Class }{ 1 Tim 5:3-10\ \textperiodcentered\ Luke 7:11-16 } & \cellcolor{cwhite}\daycell{ 5 }{ Vigil of the Ascension }{ 2nd Class }{ Eph 4:7-13\ \textperiodcentered\ John 17:1-11 } & \cellcolor{cwhite}\daycell{ 6 }{ The Ascension of Our Lord }{ 1st Class }{ Acts 1:1-11\ \textperiodcentered\ Mark 16:14-20 } & \cellcolor{cred}\daycell{ 7 }{ St. Stanislaus }{ 3rd Class }{ Wis 5:1-5\ \textperiodcentered\ John 15:1-7 } & \cellcolor{cwhite}\daycell{ 8 }{ Our Lady's Saturday Office }{ 4th Class }{ Ecclus 24:14-16\ \textperiodcentered\ John 19:25-27 } \\ \hline +\cellcolor{cwhite}\daycell{ 2 }{ 5th Sunday after Easter }{ 2nd Class }{ Jas 1:22-27\ \textperiodcentered\ John 16:23-30 } & \cellcolor{cwhite}\daycell{ 3 }{ Rogation Monday }{ 4th Class }{ Jas 1:22-27\ \textperiodcentered\ John 16:23-30 } & \cellcolor{cwhite}\daycell{ 4 }{ St. Monica }{ 3rd Class }{ 1 Tim 5:3-10\ \textperiodcentered\ Luke 7:11-16 } & \cellcolor{cwhite}\daycell{ 5 }{ Vigil of the Ascension }{ 2nd Class }{ Eph 4:7-13\ \textperiodcentered\ John 17:1-11 } & \cellcolor{cwhite}\daycell{ 6 }{ The Ascension of Our Lord }{ 1st Class }{ Acts 1:1-11\ \textperiodcentered\ Mark 16:14-20 } & \cellcolor{cred}\daycell{ 7 }{ St. Stanislaus }{ 3rd Class }{ Wis 5:1-5\ \textperiodcentered\ John 15:1-7 } & \cellcolor{cwhite}\daycell{ 8 }{ Our Lady's Saturday Office }{ 4th Class }{ Ecclus 24:14-16\ \textperiodcentered\ John 19:25-27 } \\ \hline \cellcolor{cwhite}\daycell{ 9 }{ Sunday after the Ascension }{ 2nd Class }{ 1 Pet 4:7-11\ \textperiodcentered\ John 15:26-27; 16:1-4 } & \cellcolor{cwhite}\daycell{ 10 }{ St. Antoninus }{ 3rd Class }{ Ecclus 44:16-27; 45:3-20\ \textperiodcentered\ Matt 25:14-23 } & \cellcolor{cred}\daycell{ 11 }{ Sts. Philip \& James }{ 2nd Class }{ Wis 5:1-5\ \textperiodcentered\ John 14:1-13 } & \cellcolor{cred}\daycell{ 12 }{ Sts. Nereus, Achilleus, Domitilla, \& Pancras }{ 3rd Class }{ Wis 5:1-5\ \textperiodcentered\ John 4:46-53 } & \cellcolor{cwhite}\daycell{ 13 }{ St. Robert Bellarmine }{ 3rd Class }{ Wis 7:7-14\ \textperiodcentered\ Matt 5:13-19 } & \cellcolor{cwhite}\daycell{ 14 }{ Friday of the 7th Week of Eastertide }{ 4th Class }{ 1 Pet 4:7-11\ \textperiodcentered\ John 15:26-27; 16:1-4 } & \cellcolor{cred}\daycell{ 15 }{ Vigil of Pentecost }{ 1st Class }{ Acts 19:1-8\ \textperiodcentered\ John 14:15-21 } \\ \hline \cellcolor{cred}\daycell{ 16 }{ Pentecost Sunday (Whitsunday) }{ 1st Class }{ Acts 2:1-11\ \textperiodcentered\ John 14:23-31 } & \cellcolor{cred}\daycell{ 17 }{ Monday of Pentecost Week }{ 1st Class }{ Acts 10:34, 42-48\ \textperiodcentered\ John 3:16-21 } & \cellcolor{cred}\daycell{ 18 }{ Tuesday of Pentecost Week }{ 1st Class }{ Acts 8:14-17\ \textperiodcentered\ John 10:1-10 } & \cellcolor{cred}\daycell{ 19 }{ Pentecost Ember Wednesday }{ 1st Class }{ Acts 5:12-16\ \textperiodcentered\ John 6:44-52 } & \cellcolor{cred}\daycell{ 20 }{ Thursday of Pentecost Week }{ 1st Class }{ Acts 8:5-8\ \textperiodcentered\ Luke 9:1-6 } & \cellcolor{cred}\daycell{ 21 }{ Pentecost Ember Friday }{ 1st Class }{ Joel 2:23-24; 2:26-27\ \textperiodcentered\ Luke 5:17-26 } & \cellcolor{cred}\daycell{ 22 }{ Pentecost Ember Saturday }{ 1st Class }{ Rom 5:1-5\ \textperiodcentered\ Luke 4:38-44 } \\ \hline \cellcolor{cwhite}\daycell{ 23 }{ Trinity Sunday }{ 1st Class }{ Rom 11:33-36\ \textperiodcentered\ Matt 28:18-20 } & \cellcolor{cgreen}\daycell{ 24 }{ Monday of the 1st Week of the Time after Pentecost }{ 4th Class }{ 1 John 4:8-21\ \textperiodcentered\ Luke 6:36-42 } & \cellcolor{cwhite}\daycell{ 25 }{ St. Gregory VII }{ 3rd Class }{ 1 Pet 5:1-4; 5:10-11\ \textperiodcentered\ Matt 16:13-19 } & \cellcolor{cwhite}\daycell{ 26 }{ St. Philip Neri }{ 3rd Class }{ Wis 7:7-14\ \textperiodcentered\ Luke 12:35-40 } & \cellcolor{cwhite}\daycell{ 27 }{ Corpus Christi }{ 1st Class }{ 1 Cor 11:23-29\ \textperiodcentered\ John 6:56-59 } & \cellcolor{cwhite}\daycell{ 28 }{ St. Augustine of Canterbury }{ 3rd Class }{ 1 Thess 2:2-9\ \textperiodcentered\ Luke 10:1-9 } & \cellcolor{cwhite}\daycell{ 29 }{ St. Mary Magdalene de Pazzi }{ 3rd Class }{ 2 Cor 10:17-18; 11:1-2\ \textperiodcentered\ Matt 25:1-13 } \\ \hline diff --git a/test/golden/grid-2027.typ b/test/golden/grid-2027.typ index 800edf9..b9e1d0e 100644 --- a/test/golden/grid-2027.typ +++ b/test/golden/grid-2027.typ @@ -2056,7 +2056,7 @@ - table.cell(fill: cgrid.at("violet"))[ + table.cell(fill: cgrid.at("white"))[ #block(height: cellh - 2 * cellinset, clip: true)[ #set par(leading: 0.3em) #text(weight: "bold")[3] #text(size: 6.5pt)[Rogation Monday] diff --git a/test/golden/ordo-2027.adoc b/test/golden/ordo-2027.adoc index 39e5ae4..d5660a0 100644 --- a/test/golden/ordo-2027.adoc +++ b/test/golden/ordo-2027.adoc @@ -879,7 +879,7 @@ Epistle Jas 1:22-27 Gospel John 16:23-30 *3* Rogation Monday + -class-4 · violet + +class-4 · white + Epistle Jas 1:22-27 Gospel John 16:23-30 + Commemoration Sts. Alexander & Companions diff --git a/test/golden/ordo-2027.html b/test/golden/ordo-2027.html index 8513909..1b621e4 100644 --- a/test/golden/ordo-2027.html +++ b/test/golden/ordo-2027.html @@ -672,9 +672,9 @@
class-2 · white · Epistle Jas 1:22-27 · Gospel John 16:23-30
-
+
3Rogation Monday -
class-4 · violet · Epistle Jas 1:22-27 · Gospel John 16:23-30
+
class-4 · white · Epistle Jas 1:22-27 · Gospel John 16:23-30
Commemoration Sts. Alexander & Companions
diff --git a/test/golden/ordo-2027.md b/test/golden/ordo-2027.md index 3d96240..d4acf1d 100644 --- a/test/golden/ordo-2027.md +++ b/test/golden/ordo-2027.md @@ -789,7 +789,7 @@ **3** Rogation Monday -`class-4` · violet · Epistle Jas 1:22-27 · Gospel John 16:23-30 +`class-4` · white · Epistle Jas 1:22-27 · Gospel John 16:23-30 - Commemoration Sts. Alexander & Companions diff --git a/test/golden/ordo-2027.ms b/test/golden/ordo-2027.ms index e029a76..7bc8c89 100644 --- a/test/golden/ordo-2027.ms +++ b/test/golden/ordo-2027.ms @@ -1354,7 +1354,7 @@ May .IP "3" 4 \fBRogation Monday\fR .br -\s74th Class \(bu Violet\s9 +\s74th Class \(bu White\s9 .br \s7Epistle Jas 1:22-27\s9 .br diff --git a/test/golden/ordo-2027.tex b/test/golden/ordo-2027.tex index 0db4121..e8ec59f 100644 --- a/test/golden/ordo-2027.tex +++ b/test/golden/ordo-2027.tex @@ -1548,9 +1548,9 @@ \begin{tcolorbox}[colback=white,colframe=black!35,boxrule=0.3pt,sharp corners,boxsep=0mm,left=1.6mm,right=1.6mm,top=0.4mm,bottom=0.4mm,before skip=0.3mm,after skip=0mm] -\fontsize{9}{9}\selectfont\bfseries 3 \fontsize{7}{9}\selectfont\mdseries\;Monday\hfill\swatch{licolviolet}\\ +\fontsize{9}{9}\selectfont\bfseries 3 \fontsize{7}{9}\selectfont\mdseries\;Monday\hfill\swatch{licolwhite}\\ \fontsize{9}{9.7}\selectfont\bfseries Rogation Monday\\ -\fontsize{6.5}{7.4}\selectfont\mdseries 4th Class \textperiodcentered\ Violet \quad Epistle\ Jas 1:22-27 \quad Gospel\ John 16:23-30 \\ +\fontsize{6.5}{7.4}\selectfont\mdseries 4th Class \textperiodcentered\ White \quad Epistle\ Jas 1:22-27 \quad Gospel\ John 16:23-30 \\ \fontsize{6.5}{7.4}\selectfont\mdseries Commemoration\ Sts. Alexander \& Companions \end{tcolorbox} diff --git a/test/golden/ordo-2027.txt b/test/golden/ordo-2027.txt index 0af67b3..e0073ec 100644 --- a/test/golden/ordo-2027.txt +++ b/test/golden/ordo-2027.txt @@ -728,7 +728,7 @@ May 2027 Gospel John 16:23-30 3 Rogation Monday - class-4 · violet + class-4 · white Epistle Jas 1:22-27 Gospel John 16:23-30 Commemoration Sts. Alexander & Companions diff --git a/test/golden/ordo-2027.typ b/test/golden/ordo-2027.typ index 0d87f04..ce5e0ca 100644 --- a/test/golden/ordo-2027.typ +++ b/test/golden/ordo-2027.typ @@ -1480,9 +1480,9 @@ #block(width: 100%, above: 0.4mm, below: 0mm, breakable: false, stroke: 0.4pt + luma(160), inset: (x: 1.6mm, y: 0.4mm))[ #set par(leading: 0.36em) - #text(weight: "bold")[3] #h(2mm) #text(size: 7pt)[Monday] #h(1fr) #swatch("violet") \ + #text(weight: "bold")[3] #h(2mm) #text(size: 7pt)[Monday] #h(1fr) #swatch("white") \ #text(weight: "bold")[Rogation Monday] \ - #text(size: 6.5pt)[4th Class #sym.dot.c Violet #h(2mm) Epistle Jas 1:22\-27 #h(2mm) Gospel John 16:23\-30] \ + #text(size: 6.5pt)[4th Class #sym.dot.c White #h(2mm) Epistle Jas 1:22\-27 #h(2mm) Gospel John 16:23\-30] \ #text(size: 6.5pt)[Commemoration Sts. Alexander & Companions] ] diff --git a/test/test_golden.ml b/test/test_golden.ml index d680720..3a6f3f5 100644 --- a/test/test_golden.ml +++ b/test/test_golden.ml @@ -1315,6 +1315,34 @@ let test_rogation_wednesday_yields_to_a_feast_2026 () = "2026-05-13 wednesday season=paschaltide week=6 slug=ef-ascension-vigil rank=class-2 colour=white \ subject=temporal name_la=- comms=[robert-bellarmine:ordinary] in=- out=[]" +(* ---- Rogation Monday/Tuesday colour, RG 119/128/88 (celebrant-rubrics- + phase1 Bug 1 fix, 2026-08-22; data/ef/expected-divergences-lms.sexp's + now-closed L6, data/ef/expected-divergences.sexp's reopened C8) ---- + + {!Rite_ef.Temporal_ef.temporal}'s Rogation Monday/Tuesday branch used to + hardcode [Colour.Violet] with no citation. RG 119 assigns white to the + de-Tempore Office and Mass from the Paschal Vigil to the Pentecost Vigil + exclusive -- Easter+36/+37 sit inside that window -- and RG 128's own + exhaustive four-case violet list never names Rogation days; RG 88 ("de + Litaniis minoribus nihil fit in Officio") is why -- the violet belongs + to the Rogation MASS/procession alone, not the day's own Office. Fixed + to [season_colour s], the same call every other Paschaltide feria makes. + + 2028 pins BOTH days at once (unlike the LMS witness, which only reaches + one day per fixture window): neither is impeded by a competing + sanctoral feast that year, so both are observed outright, both white. + Verified directly against `date -d`: Easter 2028-04-16, so 22/23 May are + Easter+36/+37. *) +let test_rogation_monday_white_2028 () = + check ~msg:"2028: Rogation Monday is white (RG 119), not violet" 2028 5 22 + "2028-05-22 monday season=paschaltide week=6 slug=ef-rogation-monday rank=class-4 colour=white \ + subject=temporal name_la=- comms=[] in=- out=[]" + +let test_rogation_tuesday_white_2028 () = + check ~msg:"2028: Rogation Tuesday is white (RG 119), not violet" 2028 5 23 + "2028-05-23 tuesday season=paschaltide week=6 slug=ef-rogation-tuesday rank=class-4 colour=white \ + subject=temporal name_la=- comms=[] in=- out=[]" + (* ---- The bissextile (leap-year) calendarium footnote, bissextile-shift task, 2026-08-22 ---- @@ -1572,6 +1600,10 @@ let suite = test_rogation_wednesday_admitted_2024; Alcotest.test_case "RG87/113: Rogation Wednesday yields to an impeded feast (2026)" `Quick test_rogation_wednesday_yields_to_a_feast_2026; + Alcotest.test_case "RG119/128: Rogation Monday is white, not violet (2028)" `Quick + test_rogation_monday_white_2028; + Alcotest.test_case "RG119/128: Rogation Tuesday is white, not violet (2028)" `Quick + test_rogation_tuesday_white_2028; Alcotest.test_case "bissextile footnote: Matthias moves 24->25 February (leap, 2044)" `Quick test_bissextile_matthias_leap_2044; Alcotest.test_case "bissextile footnote: Matthias unaffected (common, 2025)" `Quick diff --git a/test/test_lms_ordo.ml b/test/test_lms_ordo.ml index 00fb32c..ed1c871 100644 --- a/test/test_lms_ordo.ml +++ b/test/test_lms_ordo.ml @@ -582,17 +582,25 @@ let make_suite ~label ~fixture_path ~fixture_sha256 ~window_first ~window_last ~ | Some { MF.said = None; _ } -> "NONE (said, unexpectedly outside Votive)" | None -> "NONE") in - (* Two REAL, STRUCTURAL shapes found running this comparison (see - data/ef/expected-divergences-lms.sexp's own L5/L6 for the full - citations) -- neither is a fixed date list, both a property of the - day itself, because both recur every year the underlying condition - holds, not on a fixed calendar date the way L4 above does. Matched - by PREDICATE, not by date, for the same reason L2's own note gives - for why it is prose-only rather than wired through the shared - [expected_rows] mechanism: the count varies window to window (L5: - 6/5/6; L6: 1/0/0), so a single static count cannot check it, and - [make_suite] threads the per-window expected totals directly - (~expected_gloria_l5/~expected_gloria_l6 below) instead. *) + (* L5 is the one REAL, STRUCTURAL shape still open (see + data/ef/expected-divergences-lms.sexp's own L5 for the full + citation) -- not a fixed date list, a property of the day itself, + because it recurs every year the underlying condition holds, not on a + fixed calendar date the way L4 above does. Matched by PREDICATE, not + by date, for the same reason L2's own note gives for why it is + prose-only rather than wired through the shared [expected_rows] + mechanism: the count varies window to window (L5: 6/5/6), so a single + static count cannot check it, and [make_suite] threads the per-window + expected total directly (~expected_gloria_l5 below) instead. + + L6 is CLOSED (celebrant-rubrics-phase1, Bug 1 fix, this task): + {!Rite_ef.Temporal_ef.temporal}'s Rogation Monday/Tuesday branch no + longer hardcodes [Colour.Violet] -- see temporal_ef.ml's own citation + on that branch and data/ef/expected-divergences-lms.sexp's L6 entry + for the fix and its measured blast radius. [is_l6_rogation_colour] and + ~expected_gloria_l6 are kept, at 0 in every window, as the regression + net the same way L3's own bissextile fix keeps a predicate whose count + is now provably zero rather than deleting it. *) let is_l5_lenten_commemoration (o : ordo_row) (c : colitur_row) = (* NOT a Gloria defect (CORRECTED, l5-f3-readjudication task, 2026-08-22 -- data/ef/expected-divergences-lms.sexp's own L5 has @@ -613,15 +621,17 @@ let make_suite ~label ~fixture_path ~fixture_sha256 ~window_first ~window_last ~ (not c.c_gloria) && Option.value o.gloria ~default:false && c.c_has_commemoration && c.c_rank = V.Class3 in let is_l6_rogation_colour (o : ordo_row) (c : colitur_row) = - (* Root-caused to a DIFFERENT, pre-existing bug this comparison merely - surfaced -- {!Rite_ef.Temporal_ef.temporal}'s own Rogation Monday/ - Tuesday branch hardcodes [Colour.Violet] with no RG citation at - all, but the Ordo shows this exact date "FERIA IV Cl W" (white, - matching Paschaltide's own [season_colour] and RG88's "nihil fit in - Officio" -- the Office, hence its colour, is unchanged by the - Rogation, only the Mass TEXT is proper) -- so [gloria]'s own 432(b) - violet guard wrongly fires. NOT a Gloria defect and NOT fixed here - (out of this task's own scope; see the task report). *) + (* CLOSED (celebrant-rubrics-phase1, Bug 1 fix). Was root-caused to a + DIFFERENT, pre-existing bug this comparison merely surfaced -- + {!Rite_ef.Temporal_ef.temporal}'s own Rogation Monday/Tuesday branch + used to hardcode [Colour.Violet] with no RG citation at all, where + the Ordo shows this exact date "FERIA IV Cl W" (white, matching + Paschaltide's own [season_colour] and RG88's "nihil fit in Officio" + -- the Office, hence its colour, is unchanged by the Rogation, only + the Mass TEXT is proper) -- so [gloria]'s own 432(b) violet guard + wrongly fired. Now fixed at the source (temporal_ef.ml); this + predicate and its own ~expected_gloria_l6 count (0 in every window) + are kept as the regression net, not deleted. *) (not c.c_gloria) && Option.value o.gloria ~default:false && (contains_substring c.c_slug ~needle:"rogation-monday" || contains_substring c.c_slug ~needle:"rogation-tuesday") in @@ -788,7 +798,7 @@ let suite_2023_2024 = I-class Sunday that admits him not even as a commemoration (RG16(a)), so his own Mass is not said anywhere in this window any more. *) ~expected_bvm_votive:12 ~expected_proper:181 ~expected_common:2 ~expected_preceding_sunday:61 - ~expected_ascension_week:1 ~expected_gloria_l5:5 ~expected_gloria_l6:1 + ~expected_ascension_week:1 ~expected_gloria_l5:5 ~expected_gloria_l6:0 let suite_2024_2025 = make_suite ~label:"lms-ordo-2024-2025" ~fixture_path:"fixtures/lms-ordo-2024-2025.sexp" diff --git a/test/test_rubrics_ef.ml b/test/test_rubrics_ef.ml index 71f180d..6679702 100644 --- a/test/test_rubrics_ef.ml +++ b/test/test_rubrics_ef.ml @@ -598,6 +598,24 @@ let test_431a_mirrors_te_deum_true () = let test_432a_mirrors_te_deum_false () = check_gloria "432(a): mirrors [te_deum]=false (an ordinary Advent feria)" 2025 12 1 false +(* ---- The Rogation Monday/Tuesday cascade (celebrant-rubrics-phase1 Bug 1 + fix, 2026-08-22): {!Rite_ef.Temporal_ef.temporal} used to hardcode + [Colour.Violet] on these two days with no citation, which silenced + [gloria] via 432(b) even though 237(e)'s own Paschaltide-feria branch + already said [te_deum]=true underneath. Fixed to [season_colour] (RG + 119: white from the Paschal Vigil to the Pentecost Vigil exclusive; RG + 128's own violet list never names Rogation days; RG 88 -- the violet + belongs to the Rogation MASS, not the Office this field describes). + 2028-05-22/23: neither day is impeded that year (test_golden.ml's own + [test_rogation_{monday,tuesday}_white_2028] pins the colour side of the + same fix), so both resolve to white and both now say the Gloria, MIRROR + OF [te_deum] via 431(a) once 432(b)'s violet guard no longer fires -- + MATCHING the LMS Ordo witness (2023-2024, 2024-05-06, "FERIA IV Cl W + ... Gl"). Reverting temporal_ef.ml's fix alone (mutation-checked while + building this task) turns both [false], the pre-fix answer. *) +let test_rogation_monday_gloria_2028 () = check_gloria "Rogation Monday: white -> Gloria said (2028)" 2028 5 22 true +let test_rogation_tuesday_gloria_2028 () = check_gloria "Rogation Tuesday: white -> Gloria said (2028)" 2028 5 23 true + (* ---- Domain-wide sanity, task requirement 5: "every violet day must be false (RG 432 b), and every Requiem must be false (432 d)". Two invariants, checked over every day {!Cal.year} resolves -- [Cal.year], @@ -794,6 +812,8 @@ let suite = Alcotest.test_case "432(d): All Souls' Day (transferred)" `Quick test_432d_all_souls; Alcotest.test_case "431(a): mirrors [te_deum]=true" `Quick test_431a_mirrors_te_deum_true; Alcotest.test_case "432(a): mirrors [te_deum]=false" `Quick test_432a_mirrors_te_deum_false; + Alcotest.test_case "Rogation Monday: white -> Gloria said (2028)" `Quick test_rogation_monday_gloria_2028; + Alcotest.test_case "Rogation Tuesday: white -> Gloria said (2028)" `Quick test_rogation_tuesday_gloria_2028; Alcotest.test_case "domain sanity: every violet day has [gloria]=false (sample)" `Quick test_domain_violet_implies_no_gloria_sample; Alcotest.test_case "domain sanity: every Requiem day has [gloria]=false (sample)" `Quick -- cgit v1.3 From 9c96e0afc19925b651e0dfee3bc9182dee72acf0 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Sat, 22 Aug 2026 20:55:18 +0200 Subject: fix(ef): ferias after the Ascension repeat its own Mass, not a Sunday's Ascension has no octave under the 1960 rubrics -- confirmed structurally: the Proprium de Tempore's own table of contents runs straight from "In Ascensione Domini" to "Dominica post Ascensionem" with no per-feria headings in between. Step 3 of the reading chain therefore fell through to Preceding_sunday on every unoccupied weekday in that stretch, walking each one back to the 5th or 6th Sunday after Easter's own citation. The Missal's own Proprium de Tempore carries an explicit marginal rubric immediately after the Ascension's Mass propers, before "Dominica post Ascensionem" begins: "Diebus a feria VI post Ascensionem usque ad feriam VI ante vigiliam Pentecostes inclusive, dicitur Missa de festo Ascensionis, cum Gloria et praefatione de Ascensione, sine Credo et Communicantes proprio" -- every feria without its own proper, from the Friday after the Ascension through the Friday before the Vigil of Pentecost, repeats the Ascension's own Mass. RG 490(b) corroborates independently: it assigns the Ascension preface "tamquam de Tempore" across that identical window, which only makes sense if the Mass actually repeated there is the Ascension's, not a numbered Sunday's (whose own Mass would carry no need for a preface override at all). Witnessed directly, not only inferred from the rubric: the LMS Ordo prints "Mass of the Ascension" literally on every affected day across all three of its fixture windows, in BOTH the tail of Ascension's own week and the following week -- ruling out the alternative reading (that the second week instead resumes "Dominica post Ascensionem"'s own Mass, which a first pass over the FIUV Ordo's own week-labelled titles could suggest at a glance; its own [praef] field for the same two dates independently reads "Ascensionis", resolving the apparent conflict). Implemented as data, not logic, matching this codebase's own established precedent for the identical RG 299 shape (the week after Trinity Sunday, data/ef/lectionary.sexp's [trinity_week_entries]): six new hand-authored entries, [ascension_week_entries] in tools/bootstrap_lectionary.ml, regenerated against a git-pinned copy of lectio's own source ini (SHA-256 verified unchanged) so the regeneration carries no unrelated drift. The window's two Saturdays are deliberately excluded -- RG 78's votive Office of Our Lady on Saturday always wins an otherwise-unoccupied Class4 Saturday first, before step 2 (this fix's own entry point) is ever reached, so an entry for either slug would be dead data. Blast radius measured in-process across the full 1583-9999 domain (throwaway probe, not committed): 16 350 days total across the six slugs, every one resolved via step 2 (Own_slug), zero anomalies, and the window's two Saturdays confirmed to contribute zero hits via this cause across the whole domain, corroborating the RG78-interception reasoning by direct sweep. Closed L2 in data/ef/expected-divergences-lms.sexp. New cited entries: C41 in data/ef/expected-divergences.sexp (95 of 16801 rows, 2005-2050 -- lectio has no equivalent rubric and still walks these ferias back); M31 in data/ef/expected-divergences-missalemeum.sexp (3 rows in the 2026-2027 window, plus the same shape independently reconfirmed in the 2035 and 2038 live-capture windows) -- missalemeum, Divinum Officium's lineage, still gives the same wrong answer colitur itself used to give, which is why these rows used to agree with M18's shape and now escape it (M18 373 -> 370, the same mechanism M23-M27 established when the citation axis was first built). Golden pin: 2031-05-23, the exact date the bug report was filed against. Mutation-tested: reverting data/ef/lectionary.sexp alone (a git-diff capture/restore, not a source-code revert, since the fix is data) reddens 19 tests across the differential, both oracle fixtures, all three LMS Ordo windows, the golden pin, the lectionary unit test and every Render golden template; restored and reconfirmed green (681 tests; 683 under COLITUR_EXHAUSTIVE_SWEEP=1, ~175s). --- data/ef/expected-divergences-missalemeum.sexp | 11 +++- data/ef/expected-divergences.sexp | 11 ++++ data/ef/lectionary.sexp | 20 +++++- test/golden/grid-2027.html | 2 +- test/golden/grid-2027.ms | 2 +- test/golden/grid-2027.tex | 2 +- test/golden/grid-2027.typ | 2 +- test/golden/ordo-2027.adoc | 2 +- test/golden/ordo-2027.html | 2 +- test/golden/ordo-2027.md | 2 +- test/golden/ordo-2027.ms | 4 +- test/golden/ordo-2027.tex | 2 +- test/golden/ordo-2027.txt | 4 +- test/golden/ordo-2027.typ | 2 +- test/test_differential.ml | 18 ++++++ test/test_golden.ml | 29 +++++++++ test/test_lectionary.ml | 38 ++++++++++- test/test_lms_ordo.ml | 91 ++++++++++++++++++++++++--- test/test_oracle.ml | 47 +++++++++++++- tools/bootstrap_lectionary.ml | 70 +++++++++++++++++++++ 20 files changed, 334 insertions(+), 27 deletions(-) (limited to 'test/test_golden.ml') diff --git a/data/ef/expected-divergences-missalemeum.sexp b/data/ef/expected-divergences-missalemeum.sexp index dfee36c..d1995e2 100644 --- a/data/ef/expected-divergences-missalemeum.sexp +++ b/data/ef/expected-divergences-missalemeum.sexp @@ -257,8 +257,10 @@ REVISED, ef-bvm-saturday task: 395 of the 730 days in this window used to carry REVISED AGAIN, Task 9 (branch ef-lectionary, layer-4 oracle): 352, down by 42 from 394. NOT a change to this entry's own guard (still, and only, [diffs = [ Observed_identity_unresolved ]] exactly) -- this task compared reading citations for the first time, and 42 of the former 394 rows now ALSO carry a real [First_mismatch]/[Gospel_mismatch] alongside the pre-existing observed-identity gap, so they escape this entry's own EXACT-match guard and move to the FIVE new entries below (M23 2, M24 4, M25 4, M26 30, M27 2 -- 2+4+4+30+2=42, exactly accounting for the drop, verified against the comparator's own failure output, not assumed from the arithmetic alone -- CORRECTED, fix round 1, coordinator review: this note previously miscounted them as \"six\"). -CORRECTED, fix round 1 (coordinator review): the remaining 352 were previously described as every day whose citation \"ALREADY agreed with missalemeum before this task and still does\" -- imprecise for 18 of them. Before this task the citation axis did not exist at all, so NO row's citation was ever actually checked; \"already agreed\" wrongly implies the pre-task VALUE was correct on all 352, when for 18 it was not -- it only became correct, and therefore only started agreeing, because of this task's own three fixes (Holy Name Sunday's own two dates, 2026-01-04/2027-01-03; 12 more January-window ferias across the three RG-17(a)/Holy-Family-propers-rubric families that now resolve at step 2 instead of the walkback, one full list: 2026-01-02/05/07/08/09/12, 2027-01-04/05/07/08/11/12; and Corpus Christi/Sacred Heart in both years, 2026-06-04/06-12, 2027-05-27/06-04 -- 2+12+4=18, independently re-derived against the real resolver, not merely arithmetic). The other 334 were genuinely unaffected by this task, matching both before and after (or, more precisely, would have matched on the day this axis existed either way). WIDENED 352 -> 355 (movable-date-specs follow-up, 2026-08-17): the three Trinity-week ferias that M26 shape 2(a) used to cover now agree with the oracle on their citations and differ only on observed-identity, which is this entry own generic shape -- a temporal-origin day for which colitur sets no English name. Not a new divergence: the same three days, one of their two causes removed. WIDENED 355 -> 376 (BVM Saturday Mass, 2026-08-17): the BVM Saturday days M26 shape 1 used to cover now agree with the oracle on their citations and differ only on observed identity, which is this entry's own generic shape -- the office is temporal-origin and deliberately carries no English name. Not new divergences: the same days, their citation cause removed. CORRECTED, ef-sanctoral-status: 376 -> 373. Three rows left this entry for M30 when `ubaldus` and `didacus` were promoted to Feast on the Missal's own calendarium. They were unresolved here precisely because the observed office was TEMPORAL-origin (a feria) and carries no English name; now the observed office is the SAINT, which is sanctoral-origin and does resolve, so the comparator can state a real identity mismatch instead of declining to compare. The entry shrinks because its shape stopped occurring on those days, not because the days stopped diverging.") - (expected_rows 373)) +CORRECTED, fix round 1 (coordinator review): the remaining 352 were previously described as every day whose citation \"ALREADY agreed with missalemeum before this task and still does\" -- imprecise for 18 of them. Before this task the citation axis did not exist at all, so NO row's citation was ever actually checked; \"already agreed\" wrongly implies the pre-task VALUE was correct on all 352, when for 18 it was not -- it only became correct, and therefore only started agreeing, because of this task's own three fixes (Holy Name Sunday's own two dates, 2026-01-04/2027-01-03; 12 more January-window ferias across the three RG-17(a)/Holy-Family-propers-rubric families that now resolve at step 2 instead of the walkback, one full list: 2026-01-02/05/07/08/09/12, 2027-01-04/05/07/08/11/12; and Corpus Christi/Sacred Heart in both years, 2026-06-04/06-12, 2027-05-27/06-04 -- 2+12+4=18, independently re-derived against the real resolver, not merely arithmetic). The other 334 were genuinely unaffected by this task, matching both before and after (or, more precisely, would have matched on the day this axis existed either way). WIDENED 352 -> 355 (movable-date-specs follow-up, 2026-08-17): the three Trinity-week ferias that M26 shape 2(a) used to cover now agree with the oracle on their citations and differ only on observed-identity, which is this entry own generic shape -- a temporal-origin day for which colitur sets no English name. Not a new divergence: the same three days, one of their two causes removed. WIDENED 355 -> 376 (BVM Saturday Mass, 2026-08-17): the BVM Saturday days M26 shape 1 used to cover now agree with the oracle on their citations and differ only on observed identity, which is this entry's own generic shape -- the office is temporal-origin and deliberately carries no English name. Not new divergences: the same days, their citation cause removed. CORRECTED, ef-sanctoral-status: 376 -> 373. Three rows left this entry for M30 when `ubaldus` and `didacus` were promoted to Feast on the Missal's own calendarium. They were unresolved here precisely because the observed office was TEMPORAL-origin (a feria) and carries no English name; now the observed office is the SAINT, which is sanctoral-origin and does resolve, so the comparator can state a real identity mismatch instead of declining to compare. The entry shrinks because its shape stopped occurring on those days, not because the days stopped diverging. + +NARROWED, celebrant-rubrics-phase1 Bug 2 (2026-08-22): 373 -> 370. The three Ascension-week days (2026-05-21, 2026-05-22, 2027-05-14) move to the new M31: before this fix colitur's own citation on these three days was ALSO wrong (the same Preceding_sunday walkback missalemeum still uses), so it happened to already agree with missalemeum's, leaving [Observed_identity_unresolved] as the ONLY diff -- this entry's own shape. The fix corrected colitur's side, so these three now ALSO carry a real citation mismatch and escape this entry's exact-match guard, the identical mechanism M23-M27 above already used when the citation axis was first built. See M31's own note for the full account.") + (expected_rows 370)) ((id M19) (citation "RG 110's OTHER direction: \"In Officio et Missa S. Petri semper fit commemoratio S. Pauli, ET VICISSIM\" -- the SAME rule M12 used to cite, applied here to Paul's own office commemorating Peter, not Peter's own office commemorating Paul; confirmed a third time by the calendarium's own June table, both photographic scans, word for word: \"In Commemoratione S. Pauli Ap., III classis. / Commemoratio S. Petri Ap.\"") (verdict colitur) @@ -308,3 +310,8 @@ CORRECTED, fix round 1 (coordinator review): the remaining 352 were previously d (verdict colitur) (note "ef-sanctoral-status branch. As with M29, the oracle here is not an independent witness against colitur but colitur's own discarded ancestor: colitur was bootstrapped from lectio, lectio's ini is generated from missalemeum, and missalemeum uses Divinum Officium's data files, so all three carried the same wrong status. Found by auditing ALL 290 fixed-date sanctoral entries against the calendarium; these two were the only status defects in the file. 3 rows in this window: 2026-05-16, 2026-11-13, 2027-11-13. Where colitur now observes the saint the oracle still observes the feria, so rank, observed identity and both citations differ together and the commemoration colitur used to emit is gone. Colour differs only on 13 November, the ferial green giving way to the confessor's white; 16 May is in Paschaltide and already white. Gated on the exact dates and on a subset of that named field list, so a divergence of any other shape on these days would still surface unexplained. Three rows also leave M18 (376 to 373): they were unresolved there only because the observed office was a temporal-origin feria with no English name, and the observed office is now sanctoral and resolves.") (expected_rows 3)) + ((id M31) + (citation "The Missale Romanum's own Proprium de Tempore carries an explicit marginal rubric immediately after the Ascension's own Mass propers, before \"Dominica post Ascensionem\" begins (scan1.txt:20749-20754, both scans corroborate): \"Diebus a feria VI post Ascensionem usque ad feriam VI ante vigiliam Pentecostes inclusive, dicitur Missa de festo Ascensionis\" -- on the days from the Friday after the Ascension until the Friday before the Vigil of Pentecost inclusive, the Mass OF THE FEAST OF THE ASCENSION is said. Corroborated by RG 490(b), which assigns the Ascension preface as de Tempore across the identical window. Full account in C41, data/ef/expected-divergences.sexp. Implemented in data/ef/lectionary.sexp's [ascension_week_entries] (tools/bootstrap_lectionary.ml), celebrant-rubrics-phase1 Bug 2, 2026-08-22.") + (verdict colitur) + (note "As with M29/M30, the oracle here is colitur's own discarded ancestor, not an independent witness: missalemeum -- Divinum Officium's lineage -- still walks these ferias back to the preceding Sunday's Mass, the SAME wrong answer colitur itself gave before this fix. 3 rows in this window: 2026-05-21, 2026-05-22, 2027-05-14. Of the twelve candidate civil dates the six slugs reach across 2026 and 2027 (six per year), the other nine are occupied by real sanctoral feasts both engines already agree on: 2026-05-15/18/19/20 (John Baptist de la Salle, Venantius, Peter Celestine, Bernardine of Siena) and 2027-05-07/10/11/12/13 (Stanislaus, Antoninus, Sts Philip & James, Sts Nereus/Achilleus/Domitilla/Pancras, Robert Bellarmine) -- checked directly against `colitur day`, not assumed. [Observed_identity_unresolved] fires alongside on all three: none is a sanctoral-origin day, M18's own pre-existing limit, unrelated to this cause. Gated on the exact dates and on a subset of [Observed_identity_unresolved; First_mismatch; Gospel_mismatch] (2027-05-14 also carries a real, AGREEING commemoration -- St Boniface -- on both sides, so Comm_count/Comm_presence never differ there and stay outside this diff set). Three rows leave M18 (373 to 370): they used to carry [Observed_identity_unresolved] alone (colitur's own pre-fix citation happened to already match missalemeum's, both walking back the same wrong way) and now also carry the citation mismatch this fix corrected colitur's own side of.") + (expected_rows 3)) diff --git a/data/ef/expected-divergences.sexp b/data/ef/expected-divergences.sexp index f98409b..ca0d6a3 100644 --- a/data/ef/expected-divergences.sexp +++ b/data/ef/expected-divergences.sexp @@ -131,6 +131,17 @@ Diff shapes: most rows carry [Slug_f; Rank; Colour_f; First_f; Gospel_f] (the te BLAST RADIUS, MEASURED, full 1583-9999 domain (not merely this fixture's 2005-2050 window): 6 983 liturgical days change, zero unclassified, across all 2 041 leap years in the domain -- see data/ef/expected-divergences-lms.sexp's own now-closed L3 entry for the full figures (this entry's own 21-row 2005-2050 population is the expected subset of that domain-wide count landing inside the fixture's own window: 11 leap years x up to 2 new rows each, minus the three already-explained overlaps above).") (expected_rows 21)) + ((id C41) + (citation "The Missale Romanum's own Proprium de Tempore carries an explicit marginal rubric immediately after the Ascension's own Mass propers, before \"Dominica post Ascensionem\" begins (scan1.txt:20749-20754, both scans corroborate): \"Diebus a feria VI post Ascensionem usque ad feriam VI ante vigiliam Pentecostes inclusive, dicitur Missa de festo Ascensionis, cum Gloria et praefatione de Ascensione, sine Credo et Communicantes proprio\" -- on the days from the Friday after the Ascension until the Friday before the Vigil of Pentecost inclusive, the Mass OF THE FEAST OF THE ASCENSION is said. Corroborated by RG 490(b) (LT.txt:3981-3985), which assigns the Ascension preface \"tamquam de Tempore\" to every Mass in that same window lacking a proper preface -- consistent only if the Mass repeated is the Ascension's own, not a numbered Sunday's. Witnessed directly: the LMS Ordo prints \"Mass of the Ascension\" literally across all three fixture windows (data/ef/expected-divergences-lms.sexp's own L2, closed by this entry) on every affected day of BOTH weeks, and the FIUV Ordo's own [praef] field independently reads \"Ascensionis\" on the two analogous 2025-2026 dates its title labels by week rather than by formulary. Implemented in data/ef/lectionary.sexp's [ascension_week_entries] (tools/bootstrap_lectionary.ml), celebrant-rubrics-phase1 Bug 2, 2026-08-22.") + (verdict colitur) + (note "lectio has no equivalent rubric: it walks the six affected ferias back to the nearest preceding Sunday's Mass (5th Sunday after Easter for [ef-easter-6-friday], Dominica post Ascensionem for the five [ef-easter-7-*] weekdays), the SAME wrong answer colitur used to give before this fix. Both sides agree on slug, season (Layer A normalises colitur's [paschaltide] and lectio's [easter] as the same vocabulary), rank and colour throughout -- only the citation text differs, so every row carries [First_f; Gospel_f] alone. + +MEASURED (test_differential.ml's own [classify], 2005-2050 fixture, run directly): 95 rows, all six slugs represented, zero unclassified. Population varies year to year (0-3 of the six slugs fire per year) because most years have a real sanctoral feast occupying one or more of the six candidate civil dates -- the same reason data/ef/expected-divergences-lms.sexp's own L2 found only 1-3 affected days per its own one-year fixture windows, now confirmed at scale across the full 46-year differential window. + +The window's two Saturdays (Easter+41, Easter+48) never reach this entry: Easter+48 is the Vigil of Pentecost, a named day with its own Mass, outside the rubric's own upper bound; Easter+41 is an ordinary Class4 Saturday, so RG 78's votive Office of Our Lady on Saturday intercepts it before the lectionary lookup this entry's own fix touches is ever reached (readings' own step ordering) -- confirmed directly: no row in the 95 carries [ef-easter-6-saturday] or [ef-easter-7-saturday]. + +BLAST RADIUS, MEASURED (full 1583-9999 sweep, in-process against {!Colitur_kernel.Calendar.year}, throwaway probe, not committed): 16 350 days total, split ef-easter-6-friday 2 562, ef-easter-7-monday 2 618, ef-easter-7-tuesday 2 744, ef-easter-7-wednesday 2 776, ef-easter-7-thursday 2 781, ef-easter-7-friday 2 869 -- every one resolved via step 2's Own_slug, zero anomalies, and the window's two Saturdays confirmed to contribute zero Own_slug hits via this cause across the whole domain (RG 78's votive Office of Our Lady always intercepts first), corroborating the code-level reasoning above by direct sweep rather than inspection alone.") + (expected_rows 95)) ((id C8) (citation "RG 119 (Caput XVIII, \"De Colore Paramentorum\"): white is used \"in Officio et Missa de Tempore ... a Missa Vigiliae paschalis usque ad Missam vigiliae Pentecostes exclusive\" -- the de-Tempore Office and Mass are white from the Paschal Vigil Mass until the Pentecost Vigil Mass exclusive, and Rogation Monday/Tuesday (Easter+36/+37) sit inside that window. RG 128's own exhaustive four-case list for violet (Advent I-Christmas Eve; Septuagesima-Paschal Vigil; the September Ember ferias; vigils of II/III class OUTSIDE Paschaltide) never names Rogation days. RG 88 (\"de Litaniis minoribus nihil fit in Officio, sed tantum in Missa\"): the violet belongs to the Rogation MASS/procession, a distinct votive text this engine does not model, not to the day's own Office. Fixed in Rite_ef.Temporal_ef.temporal's Rogation branch, celebrant-rubrics-phase1 Bug 1, 2026-08-22 -- see that branch's own citation and data/ef/expected-divergences-lms.sexp's now-closed L6 entry, which is what surfaced it (LMS Ordo 2023-2024, 2024-05-06, \"FERIA IV Cl W\").") (verdict colitur) diff --git a/data/ef/lectionary.sexp b/data/ef/lectionary.sexp index a83e12e..e34622d 100644 --- a/data/ef/lectionary.sexp +++ b/data/ef/lectionary.sexp @@ -10,7 +10,7 @@ ; ; Source: ../lectio/internal/caldata/tridentine-lectionary.ini ; SHA-256: ccd6640e8c2ae4d260e62c55cfe2b3ea14ab996e8e5a82cc1b9a37bc65ac8591 -; 153 entries (119 ini sections translated/widened into colitur's own +; 159 entries (119 ini sections translated/widened into colitur's own ; Temporal_ef vocabulary via [colitur_keys]; 1 hand-authored from a ; second source file [vigil_entries]; 6 hand-authored directly from ; the Missal [holy_week_entries]; 1 hand-authored directly from the @@ -134,9 +134,27 @@ (ef-easter-5-saturday (((part First) (reference "Ecclus 24:14-16")) ((part Gospel) (reference "John 19:25-27")))) + (ef-easter-6-friday + (((part First) (reference "Acts 1:1-11")) + ((part Gospel) (reference "Mark 16:14-20")))) (ef-easter-6-saturday (((part First) (reference "Ecclus 24:14-16")) ((part Gospel) (reference "John 19:25-27")))) + (ef-easter-7-friday + (((part First) (reference "Acts 1:1-11")) + ((part Gospel) (reference "Mark 16:14-20")))) + (ef-easter-7-monday + (((part First) (reference "Acts 1:1-11")) + ((part Gospel) (reference "Mark 16:14-20")))) + (ef-easter-7-thursday + (((part First) (reference "Acts 1:1-11")) + ((part Gospel) (reference "Mark 16:14-20")))) + (ef-easter-7-tuesday + (((part First) (reference "Acts 1:1-11")) + ((part Gospel) (reference "Mark 16:14-20")))) + (ef-easter-7-wednesday + (((part First) (reference "Acts 1:1-11")) + ((part Gospel) (reference "Mark 16:14-20")))) (ef-easter-8-monday (((part First) (reference "Acts 10:34, 42-48")) ((part Gospel) (reference "John 3:16-21")))) diff --git a/test/golden/grid-2027.html b/test/golden/grid-2027.html index 6741ad7..92a73ec 100644 --- a/test/golden/grid-2027.html +++ b/test/golden/grid-2027.html @@ -134,7 +134,7 @@ 25th Sunday after EasterJas 1:22-27 · John 16:23-303Rogation MondayJas 1:22-27 · John 16:23-304St. Monica1 Tim 5:3-10 · Luke 7:11-165Vigil of the AscensionEph 4:7-13 · John 17:1-116The Ascension of Our LordActs 1:1-11 · Mark 16:14-207St. StanislausWis 5:1-5 · John 15:1-78Our Lady's Saturday OfficeEcclus 24:14-16 · John 19:25-27 - 9Sunday after the Ascension1 Pet 4:7-11 · John 15:26-27; 16:1-410St. AntoninusEcclus 44:16-27; 45:3-20 · Matt 25:14-2311Sts. Philip & JamesWis 5:1-5 · John 14:1-1312Sts. Nereus, Achilleus, Domitilla, & PancrasWis 5:1-5 · John 4:46-5313St. Robert BellarmineWis 7:7-14 · Matt 5:13-1914Friday of the 7th Week of Eastertide1 Pet 4:7-11 · John 15:26-27; 16:1-415Vigil of PentecostActs 19:1-8 · John 14:15-21 + 9Sunday after the Ascension1 Pet 4:7-11 · John 15:26-27; 16:1-410St. AntoninusEcclus 44:16-27; 45:3-20 · Matt 25:14-2311Sts. Philip & JamesWis 5:1-5 · John 14:1-1312Sts. Nereus, Achilleus, Domitilla, & PancrasWis 5:1-5 · John 4:46-5313St. Robert BellarmineWis 7:7-14 · Matt 5:13-1914Friday of the 7th Week of EastertideActs 1:1-11 · Mark 16:14-2015Vigil of PentecostActs 19:1-8 · John 14:15-21 16Pentecost Sunday (Whitsunday)Acts 2:1-11 · John 14:23-3117Monday of Pentecost WeekActs 10:34, 42-48 · John 3:16-2118Tuesday of Pentecost WeekActs 8:14-17 · John 10:1-1019Pentecost Ember WednesdayActs 5:12-16 · John 6:44-5220Thursday of Pentecost WeekActs 8:5-8 · Luke 9:1-621Pentecost Ember FridayJoel 2:23-24; 2:26-27 · Luke 5:17-2622Pentecost Ember SaturdayRom 5:1-5 · Luke 4:38-44 diff --git a/test/golden/grid-2027.ms b/test/golden/grid-2027.ms index 4f71416..3432d8f 100644 --- a/test/golden/grid-2027.ms +++ b/test/golden/grid-2027.ms @@ -767,7 +767,7 @@ T} T{ T} T{ \fB14\fP \s-2Friday of the 7th Week of Eastertide\s+2 .br -\s-21 Pet 4:7-11 \(bu John 15:26-27; 16:1-4\s+2 +\s-2Acts 1:1-11 \(bu Mark 16:14-20\s+2 T} T{ \fB15\fP \s-2Vigil of Pentecost\s+2 .br diff --git a/test/golden/grid-2027.tex b/test/golden/grid-2027.tex index d81bdb4..1585bda 100644 --- a/test/golden/grid-2027.tex +++ b/test/golden/grid-2027.tex @@ -152,7 +152,7 @@ \textbf{ Sunday } & \textbf{ Monday } & \textbf{ Tuesday } & \textbf{ Wednesday } & \textbf{ Thursday } & \textbf{ Friday } & \textbf{ Saturday } \\ \hline & & & & & & \cellcolor{cwhite}\daycell{ 1 }{ St. Joseph the Workman }{ 1st Class }{ Col 3:14-15, 17, 23-24\ \textperiodcentered\ Matt 13:54-58 } \\ \hline \cellcolor{cwhite}\daycell{ 2 }{ 5th Sunday after Easter }{ 2nd Class }{ Jas 1:22-27\ \textperiodcentered\ John 16:23-30 } & \cellcolor{cwhite}\daycell{ 3 }{ Rogation Monday }{ 4th Class }{ Jas 1:22-27\ \textperiodcentered\ John 16:23-30 } & \cellcolor{cwhite}\daycell{ 4 }{ St. Monica }{ 3rd Class }{ 1 Tim 5:3-10\ \textperiodcentered\ Luke 7:11-16 } & \cellcolor{cwhite}\daycell{ 5 }{ Vigil of the Ascension }{ 2nd Class }{ Eph 4:7-13\ \textperiodcentered\ John 17:1-11 } & \cellcolor{cwhite}\daycell{ 6 }{ The Ascension of Our Lord }{ 1st Class }{ Acts 1:1-11\ \textperiodcentered\ Mark 16:14-20 } & \cellcolor{cred}\daycell{ 7 }{ St. Stanislaus }{ 3rd Class }{ Wis 5:1-5\ \textperiodcentered\ John 15:1-7 } & \cellcolor{cwhite}\daycell{ 8 }{ Our Lady's Saturday Office }{ 4th Class }{ Ecclus 24:14-16\ \textperiodcentered\ John 19:25-27 } \\ \hline -\cellcolor{cwhite}\daycell{ 9 }{ Sunday after the Ascension }{ 2nd Class }{ 1 Pet 4:7-11\ \textperiodcentered\ John 15:26-27; 16:1-4 } & \cellcolor{cwhite}\daycell{ 10 }{ St. Antoninus }{ 3rd Class }{ Ecclus 44:16-27; 45:3-20\ \textperiodcentered\ Matt 25:14-23 } & \cellcolor{cred}\daycell{ 11 }{ Sts. Philip \& James }{ 2nd Class }{ Wis 5:1-5\ \textperiodcentered\ John 14:1-13 } & \cellcolor{cred}\daycell{ 12 }{ Sts. Nereus, Achilleus, Domitilla, \& Pancras }{ 3rd Class }{ Wis 5:1-5\ \textperiodcentered\ John 4:46-53 } & \cellcolor{cwhite}\daycell{ 13 }{ St. Robert Bellarmine }{ 3rd Class }{ Wis 7:7-14\ \textperiodcentered\ Matt 5:13-19 } & \cellcolor{cwhite}\daycell{ 14 }{ Friday of the 7th Week of Eastertide }{ 4th Class }{ 1 Pet 4:7-11\ \textperiodcentered\ John 15:26-27; 16:1-4 } & \cellcolor{cred}\daycell{ 15 }{ Vigil of Pentecost }{ 1st Class }{ Acts 19:1-8\ \textperiodcentered\ John 14:15-21 } \\ \hline +\cellcolor{cwhite}\daycell{ 9 }{ Sunday after the Ascension }{ 2nd Class }{ 1 Pet 4:7-11\ \textperiodcentered\ John 15:26-27; 16:1-4 } & \cellcolor{cwhite}\daycell{ 10 }{ St. Antoninus }{ 3rd Class }{ Ecclus 44:16-27; 45:3-20\ \textperiodcentered\ Matt 25:14-23 } & \cellcolor{cred}\daycell{ 11 }{ Sts. Philip \& James }{ 2nd Class }{ Wis 5:1-5\ \textperiodcentered\ John 14:1-13 } & \cellcolor{cred}\daycell{ 12 }{ Sts. Nereus, Achilleus, Domitilla, \& Pancras }{ 3rd Class }{ Wis 5:1-5\ \textperiodcentered\ John 4:46-53 } & \cellcolor{cwhite}\daycell{ 13 }{ St. Robert Bellarmine }{ 3rd Class }{ Wis 7:7-14\ \textperiodcentered\ Matt 5:13-19 } & \cellcolor{cwhite}\daycell{ 14 }{ Friday of the 7th Week of Eastertide }{ 4th Class }{ Acts 1:1-11\ \textperiodcentered\ Mark 16:14-20 } & \cellcolor{cred}\daycell{ 15 }{ Vigil of Pentecost }{ 1st Class }{ Acts 19:1-8\ \textperiodcentered\ John 14:15-21 } \\ \hline \cellcolor{cred}\daycell{ 16 }{ Pentecost Sunday (Whitsunday) }{ 1st Class }{ Acts 2:1-11\ \textperiodcentered\ John 14:23-31 } & \cellcolor{cred}\daycell{ 17 }{ Monday of Pentecost Week }{ 1st Class }{ Acts 10:34, 42-48\ \textperiodcentered\ John 3:16-21 } & \cellcolor{cred}\daycell{ 18 }{ Tuesday of Pentecost Week }{ 1st Class }{ Acts 8:14-17\ \textperiodcentered\ John 10:1-10 } & \cellcolor{cred}\daycell{ 19 }{ Pentecost Ember Wednesday }{ 1st Class }{ Acts 5:12-16\ \textperiodcentered\ John 6:44-52 } & \cellcolor{cred}\daycell{ 20 }{ Thursday of Pentecost Week }{ 1st Class }{ Acts 8:5-8\ \textperiodcentered\ Luke 9:1-6 } & \cellcolor{cred}\daycell{ 21 }{ Pentecost Ember Friday }{ 1st Class }{ Joel 2:23-24; 2:26-27\ \textperiodcentered\ Luke 5:17-26 } & \cellcolor{cred}\daycell{ 22 }{ Pentecost Ember Saturday }{ 1st Class }{ Rom 5:1-5\ \textperiodcentered\ Luke 4:38-44 } \\ \hline \cellcolor{cwhite}\daycell{ 23 }{ Trinity Sunday }{ 1st Class }{ Rom 11:33-36\ \textperiodcentered\ Matt 28:18-20 } & \cellcolor{cgreen}\daycell{ 24 }{ Monday of the 1st Week of the Time after Pentecost }{ 4th Class }{ 1 John 4:8-21\ \textperiodcentered\ Luke 6:36-42 } & \cellcolor{cwhite}\daycell{ 25 }{ St. Gregory VII }{ 3rd Class }{ 1 Pet 5:1-4; 5:10-11\ \textperiodcentered\ Matt 16:13-19 } & \cellcolor{cwhite}\daycell{ 26 }{ St. Philip Neri }{ 3rd Class }{ Wis 7:7-14\ \textperiodcentered\ Luke 12:35-40 } & \cellcolor{cwhite}\daycell{ 27 }{ Corpus Christi }{ 1st Class }{ 1 Cor 11:23-29\ \textperiodcentered\ John 6:56-59 } & \cellcolor{cwhite}\daycell{ 28 }{ St. Augustine of Canterbury }{ 3rd Class }{ 1 Thess 2:2-9\ \textperiodcentered\ Luke 10:1-9 } & \cellcolor{cwhite}\daycell{ 29 }{ St. Mary Magdalene de Pazzi }{ 3rd Class }{ 2 Cor 10:17-18; 11:1-2\ \textperiodcentered\ Matt 25:1-13 } \\ \hline \cellcolor{cgreen}\daycell{ 30 }{ 2nd Sunday after Pentecost }{ 2nd Class }{ 1 John 3:13-18\ \textperiodcentered\ Luke 14:16-24 } & \cellcolor{cwhite}\daycell{ 31 }{ Queenship of the Blessed Virgin Mary }{ 2nd Class }{ Ecclus 24:5; 14:7; 14:9-11; 24:30-31\ \textperiodcentered\ Luke 1:26-33 } & & & & & \\ \hline diff --git a/test/golden/grid-2027.typ b/test/golden/grid-2027.typ index b9e1d0e..cc4d440 100644 --- a/test/golden/grid-2027.typ +++ b/test/golden/grid-2027.typ @@ -2207,7 +2207,7 @@ #text(weight: "bold")[14] #text(size: 6.5pt)[Friday of the 7th Week of Eastertide] #v(1fr) #text(size: 6pt)[4th Class] \ - #text(size: 6pt)[1 Pet 4:7\-11 #sym.dot.c John 15:26\-27; 16:1\-4] + #text(size: 6pt)[Acts 1:1\-11 #sym.dot.c Mark 16:14\-20] ] ], diff --git a/test/golden/ordo-2027.adoc b/test/golden/ordo-2027.adoc index d5660a0..93a233d 100644 --- a/test/golden/ordo-2027.adoc +++ b/test/golden/ordo-2027.adoc @@ -952,7 +952,7 @@ Epistle Wis 7:7-14 Gospel Matt 5:13-19 *14* Friday of the 7th Week of Eastertide + class-4 · white + -Epistle 1 Pet 4:7-11 Gospel John 15:26-27; 16:1-4 +Epistle Acts 1:1-11 Gospel Mark 16:14-20 + Commemoration St. Boniface diff --git a/test/golden/ordo-2027.html b/test/golden/ordo-2027.html index 1b621e4..2a3f5e1 100644 --- a/test/golden/ordo-2027.html +++ b/test/golden/ordo-2027.html @@ -730,7 +730,7 @@
14Friday of the 7th Week of Eastertide -
class-4 · white · Epistle 1 Pet 4:7-11 · Gospel John 15:26-27; 16:1-4
+
class-4 · white · Epistle Acts 1:1-11 · Gospel Mark 16:14-20
Commemoration St. Boniface
diff --git a/test/golden/ordo-2027.md b/test/golden/ordo-2027.md index d4acf1d..c90b65e 100644 --- a/test/golden/ordo-2027.md +++ b/test/golden/ordo-2027.md @@ -853,7 +853,7 @@ **14** Friday of the 7th Week of Eastertide -`class-4` · white · Epistle 1 Pet 4:7-11 · Gospel John 15:26-27; 16:1-4 +`class-4` · white · Epistle Acts 1:1-11 · Gospel Mark 16:14-20 - Commemoration St. Boniface diff --git a/test/golden/ordo-2027.ms b/test/golden/ordo-2027.ms index 7bc8c89..c9e6f5e 100644 --- a/test/golden/ordo-2027.ms +++ b/test/golden/ordo-2027.ms @@ -1464,9 +1464,9 @@ May .br \s74th Class \(bu White\s9 .br -\s7Epistle 1 Pet 4:7-11\s9 +\s7Epistle Acts 1:1-11\s9 .br -\s7Gospel John 15:26-27; 16:1-4\s9 +\s7Gospel Mark 16:14-20\s9 .br \s7Commemoration St. Boniface\s9 .sp 0.25v diff --git a/test/golden/ordo-2027.tex b/test/golden/ordo-2027.tex index e8ec59f..0debd17 100644 --- a/test/golden/ordo-2027.tex +++ b/test/golden/ordo-2027.tex @@ -1648,7 +1648,7 @@ \begin{tcolorbox}[colback=white,colframe=black!35,boxrule=0.3pt,sharp corners,boxsep=0mm,left=1.6mm,right=1.6mm,top=0.4mm,bottom=0.4mm,before skip=0.3mm,after skip=0mm] \fontsize{9}{9}\selectfont\bfseries 14 \fontsize{7}{9}\selectfont\mdseries\;Friday\hfill\swatch{licolwhite}\\ \fontsize{9}{9.7}\selectfont\bfseries Friday of the 7th Week of Eastertide\\ -\fontsize{6.5}{7.4}\selectfont\mdseries 4th Class \textperiodcentered\ White \quad Epistle\ 1 Pet 4:7-11 \quad Gospel\ John 15:26-27; 16:1-4 \\ +\fontsize{6.5}{7.4}\selectfont\mdseries 4th Class \textperiodcentered\ White \quad Epistle\ Acts 1:1-11 \quad Gospel\ Mark 16:14-20 \\ \fontsize{6.5}{7.4}\selectfont\mdseries Commemoration\ St. Boniface \end{tcolorbox} diff --git a/test/golden/ordo-2027.txt b/test/golden/ordo-2027.txt index e0073ec..b2c68a3 100644 --- a/test/golden/ordo-2027.txt +++ b/test/golden/ordo-2027.txt @@ -790,8 +790,8 @@ May 2027 14 Friday of the 7th Week of Eastertide class-4 · white - Epistle 1 Pet 4:7-11 - Gospel John 15:26-27; 16:1-4 + Epistle Acts 1:1-11 + Gospel Mark 16:14-20 Commemoration St. Boniface 15 Vigil of Pentecost diff --git a/test/golden/ordo-2027.typ b/test/golden/ordo-2027.typ index ce5e0ca..23afb88 100644 --- a/test/golden/ordo-2027.typ +++ b/test/golden/ordo-2027.typ @@ -1589,7 +1589,7 @@ #set par(leading: 0.36em) #text(weight: "bold")[14] #h(2mm) #text(size: 7pt)[Friday] #h(1fr) #swatch("white") \ #text(weight: "bold")[Friday of the 7th Week of Eastertide] \ - #text(size: 6.5pt)[4th Class #sym.dot.c White #h(2mm) Epistle 1 Pet 4:7\-11 #h(2mm) Gospel John 15:26\-27; 16:1\-4] \ + #text(size: 6.5pt)[4th Class #sym.dot.c White #h(2mm) Epistle Acts 1:1\-11 #h(2mm) Gospel Mark 16:14\-20] \ #text(size: 6.5pt)[Commemoration St. Boniface] ] diff --git a/test/test_differential.ml b/test/test_differential.ml index 2f63df6..222328b 100644 --- a/test/test_differential.ml +++ b/test/test_differential.ml @@ -550,6 +550,17 @@ let jan_6_13_slug slug = let nativity_octave_day_slugs = [ "ef-nativity-octave-day-5"; "ef-nativity-octave-day-6"; "ef-nativity-octave-day-7" ] +(* C41 (celebrant-rubrics-phase1, Bug 2, 2026-08-22): the six ferias + between the Ascension and the Friday before the Vigil of Pentecost that + repeat the Ascension's own Mass (data/ef/lectionary.sexp's own + [ascension_week_entries], bootstrap_lectionary.ml). The window's two + Saturdays are excluded here too, for the identical reason they carry no + lectionary entry: RG 78's votive Office of Our Lady wins first. *) +let ascension_week_slugs = + [ "ef-easter-6-friday"; "ef-easter-7-monday"; "ef-easter-7-tuesday"; "ef-easter-7-wednesday"; + "ef-easter-7-thursday"; "ef-easter-7-friday" + ] + (* C18 (ef-sanctoral-audit, 2026-08-14): the closed set of colitur [status = Feast] sanctoral slugs whose bootstrapped [colour] was corrected against RG 124 (data/ef/adjustments.sexp's own audit-block @@ -1190,6 +1201,13 @@ let layer_c_reason (l : row) (c : row) diffs = then Some "C39" else if is_bissextile_shift_row l c ~month:m ~day:d && subset diffs [ Slug_f; Rank; Colour_f; First_f; Gospel_f ] then Some "C40" + (* C41 -- the Ascension-repeat rubric (see [ascension_week_slugs]'s own + citation above). SAME slug both sides ([Slug_f] never diffs here: the + six slugs already exist in lectio's own EF walkback, only their + resolved TEXT differs), rank/season/colour agree (both an ordinary + Class4 Paschaltide feria), and only the citation itself changes. *) + else if List.mem c.slug ascension_week_slugs && subset diffs [ First_f; Gospel_f ] + then Some "C41" (* C25 -- CLOSED, BVM Saturday Mass (2026-08-17), predicate removed: 0 rows. Its days are unoccupied IV-class Saturdays, so they carry RG 78's office and now RG 309(a)'s Mass for it, which answers before step 3's walkback diff --git a/test/test_golden.ml b/test/test_golden.ml index 3a6f3f5..c916a54 100644 --- a/test/test_golden.ml +++ b/test/test_golden.ml @@ -1281,6 +1281,33 @@ let test_readings_displaced_sunday_feria_known_divergent () = 2026 10 26 "2026-10-26 slug=ef-time-after-pentecost-22-monday first=Col 1:12-20. gospel=John 18:33-37" +(* ---- The Ascension-repeat rubric (celebrant-rubrics-phase1 Bug 2 fix, + 2026-08-22) ---- + + The Missale Romanum's own Proprium de Tempore carries an explicit + marginal rubric immediately after the Ascension's own Mass propers + (scan1.txt:20749-20754, both scans corroborate): "Diebus a feria VI post + Ascensionem usque ad feriam VI ante vigiliam Pentecostes inclusive, + dicitur Missa de festo Ascensionis" -- every feria without its own + proper, from the Friday after the Ascension through the Friday before + the Vigil of Pentecost, repeats the Ascension's own Mass (Acts 1:1-11 / + Mark 16:14-20), not the preceding Sunday's. Witnessed directly: the LMS + Ordo prints "Mass of the Ascension" literally on every affected day of + this shape across all three of its own fixture windows + (data/ef/expected-divergences-lms.sexp's own now-closed L2). + + 2031-05-23 is the exact day the bug report this task fixed was filed + against: the day after Ascension Thursday (2031-05-22, Easter+39), an + unoccupied Friday that step 3 used to walk back to + "ef-easter-sunday-6" -- the 5th Sunday after Easter, the wrong answer + -- instead of resolving at step 2 through the new + data/ef/lectionary.sexp entry. WHEN THIS PIN'S OWN VALUE WOULD REVERT TO + "Iac 1:22-27"/"Ioann 16:23-30" the fix has regressed; update it + deliberately then, never to make the suite pass again without checking + why. *) +let test_readings_ascension_week_repeat () = + check_readings ~msg:"the day after Ascension repeats the Ascension's own Mass, not the 5th Sunday after Easter's" + 2031 5 23 "2031-05-23 slug=ef-easter-6-friday first=Acts 1:1-11 gospel=Mark 16:14-20" (* ---- Rogation Wednesday (RG 87/88/89), movable-date-specs task ---- @@ -1596,6 +1623,8 @@ let suite = Alcotest.test_case "readings: displaced-Sunday feria pins M26 shape 2(b)'s KNOWN-WRONG walkback (2026-10-26)" `Quick test_readings_displaced_sunday_feria_known_divergent; + Alcotest.test_case "readings: the Ascension-repeat rubric, the reported bug's own date (2031-05-23)" `Quick + test_readings_ascension_week_repeat; Alcotest.test_case "RG87: Rogation Wednesday admitted (2024)" `Quick test_rogation_wednesday_admitted_2024; Alcotest.test_case "RG87/113: Rogation Wednesday yields to an impeded feast (2026)" `Quick diff --git a/test/test_lectionary.ml b/test/test_lectionary.ml index 7dbb253..59c739d 100644 --- a/test/test_lectionary.ml +++ b/test/test_lectionary.ml @@ -115,8 +115,14 @@ let test_ef_data_file_loads () = ([epiphanytide_opening_entries], +15); TWO hand-authored directly from the Missal, two major movable feasts with previously no entry at all ([movable_feast_entries], +2). - 116 + 1 + 6 + 1 + 2 + 3 + 2 + 15 + 2 = 148. *) - Alcotest.(check int) "entry count" 153 + 116 + 1 + 6 + 1 + 2 + 3 + 2 + 15 + 2 = 148. + celebrant-rubrics-phase1, Bug 2 (2026-08-22): SIX hand-authored + directly from the Missal's own marginal Ascension-repeat rubric + ([ascension_week_entries], +6, 153 -> 159) -- see that + function's own comment in bootstrap_lectionary.ml for the + citation and why the window's two Saturdays are deliberately + excluded. *) + Alcotest.(check int) "entry count" 159 (List.length (Lectionary.entries l)); (match Lectionary.find l (slug "ef-lent-1-monday") with | Some [ a; b ] -> @@ -179,6 +185,34 @@ let test_ef_data_file_loads () = scans). *) check_entry "ef-corpus-christi" "1 Cor 11:23-29" "John 6:56-59"; check_entry "ef-sacred-heart" "Eph 3:8-12, 14-19" "John 19:31-37"; + (* celebrant-rubrics-phase1, Bug 2: the Missal's own marginal rubric + after the Ascension's own Mass propers ("Diebus a feria VI post + Ascensionem usque ad feriam VI ante vigiliam Pentecostes + inclusive, dicitur Missa de festo Ascensionis") repeats the + Ascension's own citation on the ferias that would otherwise walk + back to the wrong Sunday. Two families pinned (the tail of + Ascension's own week; the following week), not merely one, the + same "more than one weekday" discipline this file already uses + for the Lent Ember pins above. *) + check_entry "ef-easter-6-friday" "Acts 1:1-11" "Mark 16:14-20"; + check_entry "ef-easter-7-monday" "Acts 1:1-11" "Mark 16:14-20"; + check_entry "ef-easter-7-friday" "Acts 1:1-11" "Mark 16:14-20"; + (* [ef-easter-6-saturday] keeps its own PRE-EXISTING entry, unchanged + by this task -- RG 78's votive Office of Our Lady always wins an + otherwise-unoccupied Class4 Saturday first ([readings]' own step + ordering runs that branch before step 2 is ever reached), so this + table's own value for that slug is dead data on shipped data, but + it was already there before this task and touching it is out of + scope. [ef-easter-7-saturday] must stay ABSENT instead: that civil + day is the Vigil of Pentecost, a NAMED day with its own slug and + Mass (temporal_ef.ml's own [named]), so the generic + [ef---] ferial slug this table's new + entries key off never gets produced there at all -- an entry + would be unreachable data [assert_reachable] would have refused + to emit, checked here too as a direct regression net. *) + (match Lectionary.find l (slug "ef-easter-7-saturday") with + | None -> () + | Some _ -> Alcotest.fail "ef-easter-7-saturday: must stay absent -- the Vigil of Pentecost, named, never a ferial slug"); check_entry "ef-nativity-vigil" "Rom 1:1-6" "Matt 1:18-21"; check_entry "ef-pentecost-ember-wed" "Acts 5:12-16" "John 6:44-52."; check_entry "ef-pentecost-ember-fri" "Joel 2:23-24; 26-27" "Luke 5:17-26"; diff --git a/test/test_lms_ordo.ml b/test/test_lms_ordo.ml index ed1c871..32ecfbc 100644 --- a/test/test_lms_ordo.ml +++ b/test/test_lms_ordo.ml @@ -333,7 +333,8 @@ let expected_named_sunday_override slug ~year = else None (* See Task 6's own [ascension_week_override] citation (test_lms_ordo.ml - history, expected-divergences-lms.sexp L2): STRUCTURAL, not a fixture + history, data/ef/expected-divergences-lms.sexp's own now-CLOSED L2, + celebrant-rubrics-phase1 Bug 2, 2026-08-22): STRUCTURAL, not a fixture artefact -- the Ascension is a fixed Easter+39, so every feria whose own [Preceding_sunday] fallback would otherwise resolve to a week-6/7 Sunday falls, in SOME years, between Ascension Thursday and the following @@ -341,11 +342,39 @@ let expected_named_sunday_override slug ~year = the finding: it is specifically the days AFTER Ascension (not merely "any week-6/7 Preceding_sunday day") that get this treatment -- see [expected_preceding_sunday_override]'s own citation for the Rogation - Monday counter-example that exposed the difference. [is_ascension_week] + Monday counter-example that exposed the difference. [is_after_ascension] below is the corrected predicate: the day's own DATE compared against - {!Computus.ascension} for its own year, not [n]. *) + {!Computus.ascension} for its own year, not [n]. + + FIXED (celebrant-rubrics-phase1, Bug 2): data/ef/lectionary.sexp's new + [ascension_week_entries] now answers these six ferial slugs directly at + step 2 (Own_slug), so [check_formulary_overrides]'s own [Preceding_sunday] + branch below never reaches them any more -- moved to a dedicated + [Own_slug] branch in that same function, which still asserts the Ordo's + override reads exactly [ascension_week_override], now as a genuine + confirmation that colitur's OWN citation matches (previously this + predicate only served to EXCLUDE the population from the general + Preceding_sunday mapping, because colitur had no correct answer to + compare). This constant and [is_after_ascension] itself are still load- + bearing for that confirmation -- kept, not deleted, the same "the + regression net survives its own fix" discipline + data/ef/expected-divergences-lms.sexp's own L6 note states for + [is_l6_rogation_colour]. *) let ascension_week_override = "Mass of the Ascension" +(* The exact six slugs data/ef/lectionary.sexp's own [ascension_week_entries] + (tools/bootstrap_lectionary.ml) now answers at step 2 -- gated on SLUG + IDENTITY, not merely [is_after_ascension date], because that date range + also covers "Dominica post Ascensionem" and the Vigil of Pentecost, both + genuinely [Own_slug] and both carrying their OWN, different citation, not + the Ascension's (caught live: an earlier, date-only version of this gate + wrongly flagged both as missing an Ordo override before this list was + added). *) +let ascension_week_slugs = + [ "ef-easter-6-friday"; "ef-easter-7-monday"; "ef-easter-7-tuesday"; "ef-easter-7-wednesday"; + "ef-easter-7-thursday"; "ef-easter-7-friday" + ] + (* Bounded ABOVE by Pentecost, not merely "later than Ascension" -- a bare lower bound is wrong for any date past Ascension in the SAME civil year (every date from June to December satisfies "> Ascension", which a @@ -431,7 +460,34 @@ let check_formulary_overrides ordo colitur = :: !bad | None -> bad := Printf.sprintf "%s: unmapped (colitur resumed %S) and Ordo shows no override" o.date slug :: !bad)) - | Some { MF.via = MF.Votive; _ } | Some { MF.via = MF.Own_slug; _ } | None -> ()) + | Some { MF.via = MF.Own_slug; said } -> ( + (* celebrant-rubrics-phase1, Bug 2 fix: the six Ascension-week + ferias moved from [Preceding_sunday] (the branch above, which + used to special-case them via [is_after_ascension]) to + [Own_slug] -- data/ef/lectionary.sexp's own + [ascension_week_entries] now answers at step 2, before step 3 + is ever reached. Checked HERE, not merely left to fall through + silently the way every OTHER [Own_slug] day already does + (RG 299's ordinary case, a real proper Mass, needs no Ordo + cross-check because nothing about it is adjudicated): this is + the one [Own_slug] population this suite has an OUTSIDE + witness for, and losing that check when the fix landed would + have been a silent regression net, not merely dead code -- the + Ordo's own override text must still read "Mass of the + Ascension" on exactly these days. *) + let slug = match said with Some s -> Colitur_kernel.Slug.to_string s | None -> "" in + if List.mem slug ascension_week_slugs then + match o.formulary_override with + | Some got when String.equal got ascension_week_override -> incr ascension_week + | Some got -> + bad := + Printf.sprintf "%s: colitur resolved %S via Own_slug (after Ascension), Ordo shows %S, not %S" + o.date slug got ascension_week_override + :: !bad + | None -> + bad := Printf.sprintf "%s: colitur resolved %S via Own_slug (after Ascension), Ordo shows no override" + o.date slug :: !bad) + | Some { MF.via = MF.Votive; _ } | None -> ()) pairs; { fc_bad = List.rev !bad; fc_proper = !proper; fc_common = !common; fc_preceding_sunday = !preceding_sunday; fc_ascension_week = !ascension_week } @@ -733,7 +789,7 @@ let make_suite ~label ~fixture_path ~fixture_sha256 ~window_first ~window_last ~ Alcotest.(check int) (Printf.sprintf "%d Preceding_sunday days in the window" expected_preceding_sunday) expected_preceding_sunday r.fc_preceding_sunday; Alcotest.(check int) - (Printf.sprintf "%d Preceding_sunday days fall in the Ascension-week exclusion, no more, no fewer" + (Printf.sprintf "%d Ascension-week days resolve via Own_slug and match the Ordo's own override, no more, no fewer" expected_ascension_week) expected_ascension_week r.fc_ascension_week in @@ -797,19 +853,38 @@ let suite_2023_2024 = Own_slug is excluded). Matthias himself moves to 25 February, an I-class Sunday that admits him not even as a commemoration (RG16(a)), so his own Mass is not said anywhere in this window any more. *) - ~expected_bvm_votive:12 ~expected_proper:181 ~expected_common:2 ~expected_preceding_sunday:61 + (* expected_preceding_sunday 61 -> 60 (celebrant-rubrics-phase1, Bug 2 + fix, 2026-08-22): the window's own single Ascension-week day + (2024-05-06 was BEFORE Ascension that year and never counted here in + the first place -- see [ascension_week_override]'s own citation; the + real Ascension-week day this window carries is elsewhere in May) + now resolves via Own_slug (step 2, data/ef/lectionary.sexp's new + [ascension_week_entries]), not Preceding_sunday -- it leaves this + bucket's population the same way a Proper day already does, while + expected_ascension_week itself is UNCHANGED (1): the same day is + still counted, just via check_formulary_overrides' own new + Own_slug branch instead of its Preceding_sunday one. *) + ~expected_bvm_votive:12 ~expected_proper:181 ~expected_common:2 ~expected_preceding_sunday:60 ~expected_ascension_week:1 ~expected_gloria_l5:5 ~expected_gloria_l6:0 let suite_2024_2025 = make_suite ~label:"lms-ordo-2024-2025" ~fixture_path:"fixtures/lms-ordo-2024-2025.sexp" ~fixture_sha256:"da817b75c5bf40ed3be1d5f6890b199705e02ce4d42111253ab8547bccabc3f7" ~window_first:"2024-11-27" ~window_last:"2025-12-31" ~year_lo:2023 ~year_hi:2026 ~allow_list_path ~expected_rows:400 - ~expected_bvm_votive:14 ~expected_proper:179 ~expected_common:2 ~expected_preceding_sunday:66 + (* expected_preceding_sunday 66 -> 63 (celebrant-rubrics-phase1, Bug 2 + fix): this window's own three Ascension-week days move from + Preceding_sunday to Own_slug, the same reasoning as the 2023-2024 + window's own note above; expected_ascension_week stays 3. *) + ~expected_bvm_votive:14 ~expected_proper:179 ~expected_common:2 ~expected_preceding_sunday:63 ~expected_ascension_week:3 ~expected_gloria_l5:5 ~expected_gloria_l6:0 let suite_2025_2026 = make_suite ~label:"lms-ordo-2025-2026" ~fixture_path:"fixtures/lms-ordo-2025-2026.sexp" ~fixture_sha256:"8839a61e0c7d1e6c8326114f4f45a5c183551287a88f4ed01127154add6ae5a5" ~window_first:"2025-11-28" ~window_last:"2026-12-31" ~year_lo:2024 ~year_hi:2027 ~allow_list_path ~expected_rows:399 - ~expected_bvm_votive:13 ~expected_proper:174 ~expected_common:2 ~expected_preceding_sunday:68 + (* expected_preceding_sunday 68 -> 66 (celebrant-rubrics-phase1, Bug 2 + fix): this window's own two Ascension-week days move from + Preceding_sunday to Own_slug, the same reasoning as the 2023-2024 + window's own note above; expected_ascension_week stays 2. *) + ~expected_bvm_votive:13 ~expected_proper:174 ~expected_common:2 ~expected_preceding_sunday:66 ~expected_ascension_week:2 ~expected_gloria_l5:6 ~expected_gloria_l6:0 diff --git a/test/test_oracle.ml b/test/test_oracle.ml index f1d1a89..01938e1 100644 --- a/test/test_oracle.ml +++ b/test/test_oracle.ml @@ -1381,6 +1381,33 @@ let m26_dates = citation fields are not, discovered by this task). *) let m27_dates = [ "2026-12-25"; "2027-12-25" ] +(* M31 (celebrant-rubrics-phase1, Bug 2, 2026-08-22) -- the six ferias + between the Ascension and the Friday before the Vigil of Pentecost that + repeat the Ascension's own Mass by an explicit marginal rubric in the + Proprium de Tempore (data/ef/lectionary.sexp's own [ascension_week_ + entries], full citation there and in this file's sibling + data/ef/expected-divergences.sexp's own C41). Only three of the six + civil dates this window's own [c_date] range can reach are actually + unoccupied in 2026-2027: 2026-05-21, 2026-05-22 and 2027-05-14 (the + other three fall to a real sanctoral feast both engines already agree + on). missalemeum -- Divinum Officium's own lineage, the SAME lineage + lectio inherited this defect from before colitur's own bootstrap -- + still walks these ferias back to the preceding Sunday's Mass, the + pre-fix answer colitur itself used to give; [Observed_identity_ + unresolved] fires alongside because none of the three is a SANCTORAL- + origin day (the mapping this whole file's own header describes cannot + name a TEMPORAL office's title either way, unrelated to this cause). *) +let m31_dates = [ "2026-05-21"; "2026-05-22"; "2027-05-14" ] + +(* The exact six slugs data/ef/lectionary.sexp's own [ascension_week_entries] + answers -- reused by [classify_2038]/[classify_2035] below, which key on + slug identity rather than a date list (those two live windows are not + scoped the way the 2026-2027 fixture is). *) +let ascension_week_slugs = + [ "ef-easter-6-friday"; "ef-easter-7-monday"; "ef-easter-7-tuesday"; "ef-easter-7-wednesday"; + "ef-easter-7-thursday"; "ef-easter-7-friday" + ] + (* The oracle's own row went unused when M2 -- its one reader, via [o.o_title] -- was closed/removed (see the comment above [m1_dates]), and was kept as a named, typed parameter rather than dropped from the @@ -1512,6 +1539,8 @@ let layer_m_reason (c : colitur_row) (o : oracle_row) diffs = [ Rank; Colour_f; Comm_presence; Comm_count; Observed_identity_mismatch; Comm_identity_unresolved; First_mismatch; Gospel_mismatch ] then Some "M30" + else if List.mem c.c_date m31_dates && subset diffs [ Observed_identity_unresolved; First_mismatch; Gospel_mismatch ] + then Some "M31" else None (* ---------------------------------------------------------------------- *) @@ -1992,6 +2021,16 @@ let classify_2038 (c : colitur_row) (o : oracle_row) diffs = List.mem c.c_date [ "2035-08-09"; "2035-08-14"; "2038-08-09"; "2038-08-14" ] && diffs = [ Colour_f ] then Some "VIGIL-COLOUR-RG128 (M29, colitur; see C37)" + (* The Ascension-repeat rubric (celebrant-rubrics-phase1, Bug 2; see M31 + in this file's own 2026-2027 [layer_m_reason] and C41 in + data/ef/expected-divergences.sexp for the full citation). 2038 carries + three unoccupied instances the 2026-2027 window did not (2038-06-07/ + 08/09, all week-7 weekdays); 2035 carries one (2035-05-08). Gated on + colitur's own slug rather than on the date list this window's sibling + windows use, the same style [m21_2038_slugs] already establishes for + a live-window slug-keyed class. *) + else if List.mem c.c_observed_slug ascension_week_slugs && diffs = [ First_mismatch; Gospel_mismatch ] then + Some "ASCENSION-WEEK-REPEAT (M31, colitur; register, Bug 2)" else None (* COMMEMORATIONS join the live-window comparison (2026-08-18). @@ -2129,7 +2168,13 @@ let test_2038_class_counts () = ("MISSAL-TWO-PART-CITATION (register 6.9)", 1); ("COMM-IDENTITY-UNRESOLVED (temporal-origin, no English name -- M15's limit)", 2); ("PERPETUA-COMMON (register 6.8)", 1); - ("PETER-COMPANION-ABSENT-UPSTREAM (M19)", 1) + ("PETER-COMPANION-ABSENT-UPSTREAM (M19)", 1); + (* celebrant-rubrics-phase1, Bug 2: 2038-06-07/08/09 (the Monday, + Tuesday and Wednesday of the week after the Sunday after the + Ascension) are unoccupied that year, all three landing on the + Ascension-repeat rubric -- see M31 (2026-2027 window) and C41 + (data/ef/expected-divergences.sexp) for the full citation. *) + ("ASCENSION-WEEK-REPEAT (M31, colitur; register, Bug 2)", 3) ] |> List.sort compare in diff --git a/tools/bootstrap_lectionary.ml b/tools/bootstrap_lectionary.ml index 7df290b..1e9b8ed 100644 --- a/tools/bootstrap_lectionary.ml +++ b/tools/bootstrap_lectionary.ml @@ -637,6 +637,75 @@ let trinity_week_entries = lectionary has been bitten by before. *) [ "monday"; "tuesday"; "wednesday"; "friday"; "saturday" ] +(* RG 299's own escape clause, second instance (celebrant-rubrics-phase1, + Bug 2, 2026-08-22). The Proprium de Tempore carries an explicit + marginal rubric immediately after the Ascension's own Mass propers, + before "Dominica post Ascensionem" begins (scan1.txt:20749-20754, both + scans corroborate): "Diebus a feria VI post Ascensionem usque ad + feriam VI ante vigiliam Pentecostes inclusive, dicitur Missa de festo + Ascensionis, cum Gloria et praefatione de Ascensione, sine Credo et + Communicantes proprio" -- on the days from the Friday after the + Ascension until the Friday before the Vigil of Pentecost INCLUSIVE, + the MASS OF THE FEAST OF THE ASCENSION is said (with the Gloria and + the Ascension preface, without the Creed and the proper + Communicantes). Corroborated independently by RG 490(b) (LT.txt:3981- + 3985), which assigns the Ascension preface "tamquam de Tempore" to + every Mass in that same window lacking a proper preface of its own -- + consistent only if the Mass repeated there is the Ascension's own, + not a numbered Sunday's (which would need no preface override at + all). + + Witnessed directly, not merely inferred from the rubric: the LMS Ordo + prints "Mass of the Ascension" literally, across all three fixture + windows this project has built (2023-2024: 1 day; 2024-2025: 3 days; + 2025-2026: 2 days -- data/ef/expected-divergences-lms.sexp's own L2, + closed by this entry), on EVERY affected day in BOTH the remainder of + Ascension's own week and the following week, not only the first -- + ruling out the alternative reading that the second week instead + resumes "Dominica post Ascensionem"'s own Mass. The FIUV Ordo's own + title convention for these days (2025-2026 fixture, 2026-05-21/22, + "Feria V/VI Dom. post Ascensionem, De ea") could look like the + opposite at a glance -- it is not: FIUV's title names which WEEK a + feria belongs to (a bookkeeping label, the same role colitur's own + week-numbered slug plays), while its own [praef] field for those + exact two days independently reads "Ascensionis", confirming the Mass + actually said is still the Ascension's, exactly as the marginal + rubric and RG 490(b) both require. + + The window's two Saturdays (Easter+41, Easter+48) are DELIBERATELY + NOT given entries here. Easter+48 is the Vigil of Pentecost, a named + day with its own Mass ({!Rite_ef.Temporal_ef.named}), outside the + rubric's own "usque ad feriam VI" upper bound. Easter+41 is an + ordinary IV-class Saturday, so {!Rite_ef.Lectionary_ef.readings}'s + own RG 78/RG 309(a) votive-Mass-of-Our-Lady-on-Saturday branch ALWAYS + intercepts it before step 2 is ever reached (checked directly: + [is_bvm_saturday_office] fires unconditionally on any unoccupied + Class4 Saturday, which every ordinary Paschaltide Saturday is) -- an + entry for either Saturday slug would be dead data that + [assert_reachable] cannot catch (both slugs it would name ARE real, + reachable Temporal_ef offices; the shadowing happens one level up, in + [readings]' own step ordering, not in slug reachability). + + Six ferias, matching the Ascension's own citation already given above + (Act. 1, 1-11 / Marc. 16, 14-20, scan1.txt:20701-20730, + [ef-ascension]'s own entry): the one remaining non-Saturday day of + Ascension's own week (Easter+40) and the five weekdays of the + following week (Easter+43..47), bounded above by that week's own + Friday -- the Saturday after it is the Vigil of Pentecost, named, + never reaching this table. *) +let ascension_week_citations = pair ~first:"Acts 1:1-11" ~gospel:"Mark 16:14-20" + +let ascension_week_entries = + List.map + (fun slug -> (slug_or_die slug, ascension_week_citations)) + [ "ef-easter-6-friday"; + "ef-easter-7-monday"; + "ef-easter-7-tuesday"; + "ef-easter-7-wednesday"; + "ef-easter-7-thursday"; + "ef-easter-7-friday" + ] + let epiphanytide_opening_entries = List.concat_map (fun (family, wds, cs) -> @@ -789,6 +858,7 @@ let () = translated @ vigil_entries @ holy_week_entries @ passion_tuesday_entry @ ember_saturday_corrections @ nativity_octave_entries @ holy_name_entries @ epiphanytide_opening_entries @ trinity_week_entries @ movable_feast_entries + @ ascension_week_entries in assert_reachable entries; let lect = -- cgit v1.3