aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/dune4
-rw-r--r--test/fixtures/missalemeum-ef-2026-2027.provenance39
-rw-r--r--test/fixtures/missalemeum-ef-2026-2027.txt730
-rw-r--r--test/test_colitur.ml2
-rw-r--r--test/test_oracle.ml607
5 files changed, 1380 insertions, 2 deletions
diff --git a/test/dune b/test/dune
index 1803e75..714ffb2 100644
--- a/test/dune
+++ b/test/dune
@@ -5,7 +5,9 @@
../data/ef/sanctoral.sexp
../data/ef/adjustments.sexp
../data/ef/expected-divergences.sexp
- fixtures/lectio-ef-2005-2050.txt)
+ ../data/ef/expected-divergences-missalemeum.sexp
+ fixtures/lectio-ef-2005-2050.txt
+ fixtures/missalemeum-ef-2026-2027.txt)
(preprocess
(pps ppx_sexp_conv)))
diff --git a/test/fixtures/missalemeum-ef-2026-2027.provenance b/test/fixtures/missalemeum-ef-2026-2027.provenance
new file mode 100644
index 0000000..576093d
--- /dev/null
+++ b/test/fixtures/missalemeum-ef-2026-2027.provenance
@@ -0,0 +1,39 @@
+Fixture: missalemeum-ef-2026-2027.txt
+Task: 2026-08-11-colitur-plan3-resolution-engine, Task 16 (oracle harness +
+data audit)
+
+Source: missalemeum.com (Divinum Officium data), archived by the sibling
+project ~/git/projects/lectio at:
+ commit d7da4b0 "sources: store the snapshot as one compressed archive"
+ path sources/snapshot.tar.gz, entries missalemeum/en/YYYY-MM-DD.json
+ (lectio/sources/README.md: "First archived 2026-07-29")
+
+SHA-256 of the extracted fixture: 718eff1a03fa09c3927ef18d19fe7921c2d4d7611890c22566058b81fd7cc5ea
+(same digest as [fixture_sha256] in test/test_oracle.ml, ASSERTED by that
+suite's own "fixture SHA-256 matches its provenance note" test -- this line
+documents the pin for a reader who never runs the suite; that test is what
+actually enforces it. Regenerate both together, deliberately, after
+re-running the exact command below -- never by copying a mismatch's actual
+value back in, which would defeat the pin's purpose.)
+
+Exact commands:
+ cd ~/git/projects/lectio && sh scripts/snapshot-sources.sh unpack
+ python3 ~/git/projects/colitur/tools/extract_missalemeum_oracle.py \
+ ~/git/projects/lectio/sources \
+ ~/git/projects/colitur/test/fixtures/missalemeum-ef-2026-2027.txt
+
+Output: one line per civil day, 2026-01-01 through 2027-12-31 inclusive
+(730 lines = 365 + 365, both non-leap years), pipe-separated:
+ date|rank|colors|title|tempora|commemorations|displaced|n_masses
+See tools/extract_missalemeum_oracle.py's own header for the exact field
+semantics (info.rank/colors/title/tempora/commemorations/displaced,
+verbatim English strings, not translated or slugified) and the two things
+verified during extraction, not merely assumed: no field collides with the
+"|"/";" delimiters, and all 4 multi-Mass days (info is an array on
+2026-11-02, 2026-12-25, 2027-11-02, 2027-12-25) carry an IDENTICAL info
+block (rank/colors/tempora/commemorations/displaced) across every Mass of
+the day, so taking entry[0] throughout (this fixture's own convention)
+loses nothing the comparator or a human auditor needs.
+
+Regenerate with the same commands if the missalemeum snapshot is refreshed
+and the fixture needs updating; do not hand-edit this file or the fixture.
diff --git a/test/fixtures/missalemeum-ef-2026-2027.txt b/test/fixtures/missalemeum-ef-2026-2027.txt
new file mode 100644
index 0000000..d000212
--- /dev/null
+++ b/test/fixtures/missalemeum-ef-2026-2027.txt
@@ -0,0 +1,730 @@
+2026-01-01|1|w|Octave Day of Christmas|-|-|-|1
+2026-01-02|4|w|Feria|-|-|-|1
+2026-01-03|4|w|II Mass of the B. V. M. – Vultum Tuum|-|-|-|1
+2026-01-04|2|w|Holy Name of Jesus|-|-|-|1
+2026-01-05|4|w|Feria|-|St. Telesphorus Pope and Martyr|-|1
+2026-01-06|1|w|Epiphany of the Lord|-|-|-|1
+2026-01-07|4|w|Feria|-|-|-|1
+2026-01-08|4|w|Feria|-|-|-|1
+2026-01-09|4|w|Feria|-|-|-|1
+2026-01-10|4|w|II Mass of the B. V. M. – Vultum Tuum|-|-|-|1
+2026-01-11|2|w|The Holy Family: Jesus, Mary & Joseph|-|-|St. Hyginus Pope and Martyr|1
+2026-01-12|4|w|Feria|Feria_II_after_Epiphany|-|-|1
+2026-01-13|2|w|Commemoration of the Baptism of the Lord|Feria_III_after_Epiphany|-|-|1
+2026-01-14|3|w|St. Hilary|Feria_IV_after_Epiphany|S. Felicis|-|1
+2026-01-15|3|w|St. Paul, the First Hermit|Feria_V_after_Epiphany|St. Maur, Abbot|-|1
+2026-01-16|3|r|St. Marcellus I|Feria_VI_after_Epiphany|-|-|1
+2026-01-17|3|w|St. Anthony|Saturday_after_Epiphany|-|-|1
+2026-01-18|2|g|II Sunday after Epiphany|-|-|St. Prisca|1
+2026-01-19|4|g|Feria|Feria_II_after_II_Sunday_after_Epiphany|Sts. Marius, Martha, Audifax & Abachum;St. Canute, Martyr|-|1
+2026-01-20|3|r|Sts. Fabian & Sebastian|Feria_III_after_II_Sunday_after_Epiphany|-|-|1
+2026-01-21|3|r|St. Agnes|Feria_IV_after_II_Sunday_after_Epiphany|-|-|1
+2026-01-22|3|r|Sts. Vincent & Anastasius|Feria_V_after_II_Sunday_after_Epiphany|-|-|1
+2026-01-23|3|w|St. Raymond of Peñafort|Feria_VI_after_II_Sunday_after_Epiphany|St. Emerentiana|-|1
+2026-01-24|3|r|St. Timothy|Saturday_after_II_Sunday_after_Epiphany|-|-|1
+2026-01-25|2|g|III Sunday after Epiphany|-|-|Conversion of St. Paul;St. Peter|1
+2026-01-26|3|r|St. Polycarp|Feria_II_after_III_Sunday_after_Epiphany|-|-|1
+2026-01-27|3|w|St. John Chrysostom|Feria_III_after_III_Sunday_after_Epiphany|-|-|1
+2026-01-28|3|w|St. Peter Nolasco|Feria_IV_after_III_Sunday_after_Epiphany|St. Agnes|-|1
+2026-01-29|3|w|St. Francis de Sales|Feria_V_after_III_Sunday_after_Epiphany|-|-|1
+2026-01-30|3|r|St. Martina|Feria_VI_after_III_Sunday_after_Epiphany|-|-|1
+2026-01-31|3|w|St. John Bosco|Saturday_after_III_Sunday_after_Epiphany|-|-|1
+2026-02-01|2|v|Septuagesima Sunday|-|-|St. Ignatius of Antioch|1
+2026-02-02|2|w|Purification of the Blessed Virgin Mary|Feria_II_after_Septuagesima|-|-|1
+2026-02-03|4|v|Feria|Feria_III_after_Septuagesima|St. Blaise|-|1
+2026-02-04|3|w|St. Andrew Corsini|Feria_IV_after_Septuagesima|-|-|1
+2026-02-05|3|r|St. Agatha|Feria_V_after_Septuagesima|-|-|1
+2026-02-06|3|w|St. Titus|Feria_VI_after_Septuagesima|St. Dorothy|-|1
+2026-02-07|3|w|St. Romuald|Saturday_after_Septuagesima|-|-|1
+2026-02-08|2|v|Sexagesima Sunday|-|-|St. John of Matha|1
+2026-02-09|3|w|St. Cyril of Alexandria|Feria_II_after_Sexagesima|St. Appollonia|-|1
+2026-02-10|3|w|St. Scholastica|Feria_III_after_Sexagesimæ|-|-|1
+2026-02-11|3|w|Our Lady of Lourdes|Feria_IV_after_Sexagesimæ|-|-|1
+2026-02-12|3|w|Seven Holy Servite Founders|Feria_V_after_Sexagesimæ|-|-|1
+2026-02-13|4|v|Feria|Feria_VI_after_Sexagesimæ|-|-|1
+2026-02-14|4|w|III Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_Sexagesimæ|St. Valentine|-|1
+2026-02-15|2|v|Quinquagesima Sunday|-|-|Sts. Faustinus & Jovita|1
+2026-02-16|4|v|Feria|Feria_II_after_Quinquagesima|-|-|1
+2026-02-17|4|v|Feria|Feria_III_after_Quinquagesima|-|-|1
+2026-02-18|1|v|Ash Wednesday|-|-|St. Simeon|1
+2026-02-19|3|v|Feria V after Ash Wednesday|-|-|-|1
+2026-02-20|3|v|Feria VI after Ash Wednesday|-|-|-|1
+2026-02-21|3|v|Saturday after Ash Wednesday|-|-|-|1
+2026-02-22|1|v|I Sunday of Lent|-|-|Chair of St. Peter;St. Paul|1
+2026-02-23|3|v|Feria II after the I Sunday of Lent|-|St. Peter Damien|-|1
+2026-02-24|2|r|St. Matthias|Feria_III_after_the_I_Sunday_of_Lent|Feria III after the I Sunday of Lent|-|1
+2026-02-25|2|v|Ember Wednesday of Lent|-|-|-|1
+2026-02-26|3|v|Feria V after the I Sunday of Lent|-|-|-|1
+2026-02-27|2|v|Ember Friday of Lent|-|St. Gabriel of Our Lady of Sorrows|-|1
+2026-02-28|2|v|Ember Saturday of Lent|-|-|-|1
+2026-03-01|1|v|II Sunday of Lent|-|-|-|1
+2026-03-02|3|v|Feria II after the II Sunday of Lent|-|-|-|1
+2026-03-03|3|v|Feria III after the II Sunday of Lent|-|-|-|1
+2026-03-04|3|v|Feria IV after the II Sunday of Lent|-|St. Casimir;St. Lucius|-|1
+2026-03-05|3|v|Feria V after the II Sunday of Lent|-|-|-|1
+2026-03-06|3|v|Feria VI after the II Sunday of Lent|-|Sts. Felicitas & Perpetua|-|1
+2026-03-07|3|v|Saturday after the II Sunday of Lent|-|St. Thomas Aquinas|-|1
+2026-03-08|1|v|III Sunday of Lent|-|-|St. John of God|1
+2026-03-09|3|v|Feria II after the III Sunday of Lent|-|St. Frances Rome|-|1
+2026-03-10|3|v|Feria III after the III Sunday of Lent|-|Forty Holy Martyrs of Sebaste|-|1
+2026-03-11|3|v|Feria IV after the III Sunday of Lent|-|-|-|1
+2026-03-12|3|v|Feria V after the III Sunday of Lent|-|St. Gregory the Great|-|1
+2026-03-13|3|v|Feria VI after the III Sunday of Lent|-|-|-|1
+2026-03-14|3|v|Saturday after the III Sunday of Lent|-|-|-|1
+2026-03-15|1|pv|IV Sunday of Lent|-|-|-|1
+2026-03-16|3|v|Feria II after the IV Sunday of Lent|-|-|-|1
+2026-03-17|3|v|Feria III after the IV Sunday of Lent|-|St. Patrick|-|1
+2026-03-18|3|v|Feria IV after the IV Sunday of Lent|-|St. Cyril of Jerusalem|-|1
+2026-03-19|1|w|St. Joseph, Spouse of the Bl. Virgin Mary|Feria_V_after_the_IV_Sunday_of_Lent|Feria V after the IV Sunday of Lent|-|1
+2026-03-20|3|v|Feria VI after the IV Sunday of Lent|-|-|-|1
+2026-03-21|3|v|Saturday after the IV Sunday of Lent|-|St. Benedict|-|1
+2026-03-22|1|v|Passion Sunday|-|-|-|1
+2026-03-23|3|v|Feria II of Passion Week|-|-|-|1
+2026-03-24|3|v|Feria III of Passion Week|-|St. Gabriel the Archangel|-|1
+2026-03-25|1|w|Annunciation of the Blessed Virgin Mary|Feria_IV_of_Passion_Week|Feria IV of Passion Week|-|1
+2026-03-26|3|v|Feria V of Passion Week|-|-|-|1
+2026-03-27|3|v|Feria VI of Passion Week|-|For Our Lady of the Seven Sorrows|St. John Damascene|1
+2026-03-28|3|v|Saturday of Passion Week|-|St. John of Capistrano|-|1
+2026-03-29|1|rv|Palm Sunday|-|-|-|1
+2026-03-30|1|v|Feria II of Holy Week|-|-|-|1
+2026-03-31|1|v|Feria III of Holy Week|-|-|-|1
+2026-04-01|1|v|Feria IV of Holy Week|-|-|-|1
+2026-04-02|1|w|Holy Thursday|-|-|St. Francis of Paola|1
+2026-04-03|1|bv|Good Friday|-|-|-|1
+2026-04-04|1|vw|Holy Saturday|-|-|St. Isidore of Seville|1
+2026-04-05|1|w|Easter Sunday|-|-|St. Vincent Ferrer|1
+2026-04-06|1|w|Monday in the Octave of Easter|-|-|-|1
+2026-04-07|1|w|Tuesday in the Octave of Easter|-|-|-|1
+2026-04-08|1|w|Wednesday in the Octave of Easter|-|-|-|1
+2026-04-09|1|w|Thursday in the Octave of Easter|-|-|-|1
+2026-04-10|1|w|Friday in the Octave of Easter|-|-|-|1
+2026-04-11|1|w|Saturday in the Octave of Easter|-|-|St. Leo the Great|1
+2026-04-12|1|w|Low Sunday|-|-|-|1
+2026-04-13|3|r|St. Hermenegild|Monday_after_I_Sunday_after_Easter|-|-|1
+2026-04-14|3|r|St. Justin|Tuesday_after_I_Sunday_after_Easter|Sts. Tiburtius, Valerian et Maximus, Martyrs|-|1
+2026-04-15|4|w|Feria|Wednesday_after_I_Sunday_after_Easter|-|-|1
+2026-04-16|4|w|Feria|Thursday_after_I_Sunday_after_Easter|-|-|1
+2026-04-17|4|w|Feria|Friday_after_I_Sunday_after_Easter|St. Anicetus|-|1
+2026-04-18|4|w|IV Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_I_Sunday_after_Easter|-|-|1
+2026-04-19|2|w|II Sunday after Easter|-|-|-|1
+2026-04-20|4|w|Feria|Monday_after_II_Sunday_after_Easter|-|-|1
+2026-04-21|3|w|St. Anselm|Tuesday_after_II_Sunday_after_Easter|-|-|1
+2026-04-22|3|r|Sts. Soter & Caius|Wednesday_after_II_Sunday_after_Easter|-|-|1
+2026-04-23|4|w|Feria|Thursday_after_II_Sunday_after_Easter|St. George|-|1
+2026-04-24|3|r|St. Fidelis of Sigmaringen|Friday_after_II_Sunday_after_Easter|-|-|1
+2026-04-25|2|r|St. Mark|Saturday_after_II_Sunday_after_Easter|Pro rogationibus|-|1
+2026-04-26|2|w|III Sunday after Easter|-|-|Sts. Cletus & Marcellinus|1
+2026-04-27|3|w|St. Peter Canisius|Monday_after_III_Sunday_after_Easter|-|-|1
+2026-04-28|3|w|St. Paul of the Cross|Tuesday_after_III_Sunday_after_Easter|-|-|1
+2026-04-29|3|r|St. Peter of Verona|Wednesday_after_III_Sunday_after_Easter|-|-|1
+2026-04-30|3|w|St. Catherine of Siena|Thursday_after_III_Sunday_after_Easter|-|-|1
+2026-05-01|1|w|St. Joseph the Workman|Friday_after_III_Sunday_after_Easter|-|-|1
+2026-05-02|3|w|St. Athanasius|Saturday_after_III_Sunday_after_Easter|-|-|1
+2026-05-03|2|w|IV Sunday after Easter|-|-|Sts. Alexander & Companions|1
+2026-05-04|3|w|St. Monica|Monday_after_IV_Sunday_after_Easter|-|-|1
+2026-05-05|3|w|St. Pius V|Tuesday_after_IV_Sunday_after_Easter|-|-|1
+2026-05-06|4|w|Feria|Wednesday_after_IV_Sunday_after_Easter|-|-|1
+2026-05-07|3|r|St. Stanislaus|Thursday_after_IV_Sunday_after_Easter|-|-|1
+2026-05-08|4|w|Feria|Friday_after_IV_Sunday_after_Easter|-|-|1
+2026-05-09|3|w|St. Gregory of Nazianzen|Saturday_after_IV_Sunday_after_Easter|-|-|1
+2026-05-10|2|w|V Sunday after Easter|-|-|St. Antoninus;St. Gordiano and Epimacho|1
+2026-05-11|2|r|Sts. Philip & James|The_Minor_Litanies_–_Rogations|-|-|1
+2026-05-12|3|r|Sts. Nereus, Achilleus, Domitilla, & Pancras|The_Minor_Litanies_–_Rogations|-|-|1
+2026-05-13|2|w|Vigil of the Ascension|-|St. Robert Bellarmine|-|1
+2026-05-14|1|w|Ascension of the Lord|-|-|St. Boniface|1
+2026-05-15|3|w|St. John Baptist de la Salle|Feria_VI_after_the_Ascension|-|-|1
+2026-05-16|4|w|IV Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_the_Ascension|St. Ubaldus|-|1
+2026-05-17|2|w|Sunday after the Ascension|-|-|St. Paschal Baylon|1
+2026-05-18|3|r|St. Venantius|Feria_II_after_the_Ascension|-|-|1
+2026-05-19|3|w|St. Peter Celestine|Feria_III_after_the_Ascension|St. Pudentiana Virginis|-|1
+2026-05-20|3|w|St. Bernardine of Siena|Feria_IV_after_the_Ascension|-|-|1
+2026-05-21|4|w|Feria|Feria_V_after_the_Ascension|-|-|1
+2026-05-22|4|w|Feria|Feria_VI_after_the_Ascension|-|-|1
+2026-05-23|1|r|Saturday after the Ascension|-|-|-|1
+2026-05-24|1|r|Pentecost Sunday|-|-|-|1
+2026-05-25|1|r|Monday after Pentecost|-|-|St. Gregory VII;St. Urban, Pope and Martyr|1
+2026-05-26|1|r|Tuesday after Pentecost|-|-|St. Philip Neri;S. Eleutherius|1
+2026-05-27|1|r|Ember Wednesday of Pentecost|-|-|St. Bede the Venerable;St. John I|1
+2026-05-28|1|r|Thursday after Pentecost|-|-|St. Augustine of Canterbury|1
+2026-05-29|1|r|Ember Friday of Pentecost|-|-|St. Mary Magdalene de Pazzi|1
+2026-05-30|1|r|Ember Saturday of Pentecost|-|-|St. Felix I|1
+2026-05-31|1|w|Trinity Sunday|-|-|Queenship of the Blessed Virgin Mary;St. Petronilla|1
+2026-06-01|3|w|St. Angela Merici|Feria_II_after_I_Sunday_after_Pentecost|-|-|1
+2026-06-02|4|g|Feria|Feria_III_after_I_Sunday_after_Pentecost|Sts. Marcellinus, Peter, & Erasmus|-|1
+2026-06-03|4|g|Feria|Feria_IV_after_I_Sunday_after_Pentecost|-|-|1
+2026-06-04|1|w|Corpus Christi|-|-|St. Francis Caracciolo|1
+2026-06-05|3|r|St. Boniface|Feria_V_after_I_Sunday_after_Pentecost|-|-|1
+2026-06-06|3|w|St. Norbert|Saturday_after_I_Sunday_after_Pentecost|-|-|1
+2026-06-07|2|g|II Sunday after Pentecost|-|-|-|1
+2026-06-08|4|g|Feria|Feria_II_after_II_Sunday_after_Pentecost|-|-|1
+2026-06-09|4|g|Feria|Feria_III_after_II_Sunday_after_Pentecost|Sts. Primus & Felicianus|-|1
+2026-06-10|3|w|St. Margaret of Scotland|Feria_IV_after_II_Sunday_after_Pentecost|-|-|1
+2026-06-11|3|r|St. Barnabas|Feria_V_after_II_Sunday_after_Pentecost|-|-|1
+2026-06-12|1|w|Sacred Heart of Jesus|-|-|St. John of San Fecundo;St. Basilidus|1
+2026-06-13|3|w|St. Anthony of Padua|Saturday_after_II_Sunday_after_Pentecost|-|-|1
+2026-06-14|2|g|III Sunday after Pentecost|-|-|St. Basil the Great|1
+2026-06-15|4|g|Feria|Feria_II_after_III_Sunday_after_Pentecost|St. Vitus|-|1
+2026-06-16|4|g|Feria|Feria_III_after_III_Sunday_after_Pentecost|-|-|1
+2026-06-17|3|w|St. Gregory Barbarigo|Feria_IV_after_III_Sunday_after_Pentecost|-|-|1
+2026-06-18|3|r|St. Ephrem of Syria|Feria_V_after_III_Sunday_after_Pentecost|Ss. Marcus and Marcellianus|-|1
+2026-06-19|3|r|St. Julia of Falconieri|Feria_VI_after_III_Sunday_after_Pentecost|Sts. Gervasius and Protasius|-|1
+2026-06-20|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_III_Sunday_after_Pentecost|St. Silverius|-|1
+2026-06-21|2|g|IV Sunday after Pentecost|-|-|St. Aloysius Gongzaga|1
+2026-06-22|3|w|St. Paulinus of Nola|Feria_II_after_IV_Sunday_after_Pentecost|-|-|1
+2026-06-23|2|v|Vigil of the Nativity of St. John the Baptist|Feria_III_after_IV_Sunday_after_Pentecost|-|-|1
+2026-06-24|1|w|Nativity of St. John the Baptist|Feria_IV_after_IV_Sunday_after_Pentecost|-|-|1
+2026-06-25|3|w|St. William|Feria_V_after_IV_Sunday_after_Pentecost|-|-|1
+2026-06-26|3|r|Sts. John & Paul|Feria_VI_after_IV_Sunday_after_Pentecost|-|-|1
+2026-06-27|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_IV_Sunday_after_Pentecost|-|-|1
+2026-06-28|2|g|V Sunday after Pentecost|-|Vigil of Sts. Peter & Paul|-|1
+2026-06-29|1|r|Sts. Peter & Paul|Feria_II_after_V_Sunday_after_Pentecost|-|-|1
+2026-06-30|3|r|In Commemoratione Sancti Pauli Apostoli|Feria_III_after_V_Sunday_after_Pentecost|-|-|1
+2026-07-01|1|r|The Precious Blood of Our Lord Jesus Christ|Feria_IV_after_V_Sunday_after_Pentecost|-|-|1
+2026-07-02|2|w|Visitation of the Blessed Virgin Mary|Feria_V_after_V_Sunday_after_Pentecost|SS. Processus and Martinian|-|1
+2026-07-03|3|r|St. Irenaeus|Feria_VI_after_V_Sunday_after_Pentecost|-|-|1
+2026-07-04|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_V_Sunday_after_Pentecost|-|-|1
+2026-07-05|2|g|VI Sunday after Pentecost|-|-|St. Anthony Mary Zaccariah|1
+2026-07-06|4|g|Feria|Feria_II_after_VI_Sunday_after_Pentecost|-|-|1
+2026-07-07|3|w|Sts. Cyril & Methodius|Feria_III_after_VI_Sunday_after_Pentecost|-|-|1
+2026-07-08|3|w|St. Elizabeth of Portugal|Feria_IV_after_VI_Sunday_after_Pentecost|-|-|1
+2026-07-09|4|g|Feria|Feria_V_after_VI_Sunday_after_Pentecost|-|-|1
+2026-07-10|3|r|Seven Holy Brothers and Sts. Rufina & Secunda|Feria_VI_after_VI_Sunday_after_Pentecost|-|-|1
+2026-07-11|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_VI_Sunday_after_Pentecost|St. Pius I|-|1
+2026-07-12|2|g|VII Sunday after Pentecost|-|-|St. John Gualbert;Ss. Naboris et Felicis|1
+2026-07-13|4|g|Feria|Feria_II_after_VII_Sunday_after_Pentecost|-|-|1
+2026-07-14|3|w|St. Bonaventure|Feria_III_after_VII_Sunday_after_Pentecost|-|-|1
+2026-07-15|3|w|St. Henry the Emperor|Feria_IV_after_VII_Sunday_after_Pentecost|-|-|1
+2026-07-16|4|g|Feria|Feria_V_after_VII_Sunday_after_Pentecost|Our Lady of Mt. Carmel|-|1
+2026-07-17|4|g|Feria|Feria_VI_after_VII_Sunday_after_Pentecost|St. Alexis|-|1
+2026-07-18|3|r|Camillus de Lellis|Saturday_after_VII_Sunday_after_Pentecost|Ss. Symphorosa and sons|-|1
+2026-07-19|2|g|VIII Sunday after Pentecost|-|-|St. Vincent de Paul|1
+2026-07-20|3|r|St. Jerome Emiliani|Feria_II_after_VIII_Sunday_after_Pentecost|St. Margaret|-|1
+2026-07-21|3|w|St. Laurence of Brindisi|Feria_III_after_VIII_Sunday_after_Pentecost|St. Praxedis Virginis|-|1
+2026-07-22|3|w|St. Mary Magdalene|Feria_IV_after_VIII_Sunday_after_Pentecost|-|-|1
+2026-07-23|3|w|St. Apollinaris|Feria_V_after_VIII_Sunday_after_Pentecost|S. Liborii|-|1
+2026-07-24|4|g|Feria|Feria_VI_after_VIII_Sunday_after_Pentecost|St. Christina|-|1
+2026-07-25|2|r|St. James the Greater|Saturday_after_VIII_Sunday_after_Pentecost|St. Christopher|-|1
+2026-07-26|2|g|IX Sunday after Pentecost|-|St. Anne, Mother of the Blessed Virgin|-|1
+2026-07-27|4|g|Feria|Feria_II_after_IX_Sunday_after_Pentecost|St. Pantaleon|-|1
+2026-07-28|3|r|Sts. Nazarius & Celsus, St. Victor I & St. Innocent I|Feria_III_after_IX_Sunday_after_Pentecost|-|-|1
+2026-07-29|3|r|St. Martha|Feria_IV_after_IX_Sunday_after_Pentecost|Ss. Felicis, Simplicii, Faustini et Beatricis|-|1
+2026-07-30|4|g|Feria|Feria_V_after_IX_Sunday_after_Pentecost|Sts. Abdon & Sennen|-|1
+2026-07-31|3|w|St. Ignatius Loyola|Feria_VI_after_IX_Sunday_after_Pentecost|-|-|1
+2026-08-01|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_IX_Sunday_after_Pentecost|Holy Machabees|-|1
+2026-08-02|2|g|X Sunday after Pentecost|-|-|St. Alphonsus Liguori;St. Stephen I, Pope and Martyr|1
+2026-08-03|4|g|Feria|Feria_II_after_X_Sunday_after_Pentecost|-|-|1
+2026-08-04|3|w|St. Dominic|Feria_III_after_X_Sunday_after_Pentecost|-|-|1
+2026-08-05|3|w|Dedication of the Basilica of St. Mary Major|Feria_IV_after_X_Sunday_after_Pentecost|-|-|1
+2026-08-06|2|w|Transfiguration of Our Lord|Feria_V_after_X_Sunday_after_Pentecost|Pope Sixtus II, Felicissimus and Agapitus, Martyrs|-|1
+2026-08-07|3|w|St. Cajetan|Feria_VI_after_X_Sunday_after_Pentecost|St. Donatus|-|1
+2026-08-08|3|w|St. John Mary Vianney|Saturday_after_X_Sunday_after_Pentecost|Ss. Cyriacus, Largus and Smaragdus, Martyrs|-|1
+2026-08-09|3|r|Vigil of St. Lawrence|XI_Sunday_after_Pentecost|St. Romanus|-|1
+2026-08-10|2|r|St. Lawrence|Feria_II_after_XI_Sunday_after_Pentecost|-|-|1
+2026-08-11|4|g|Feria|Feria_III_after_XI_Sunday_after_Pentecost|Sts. Tiburtius & Susanna|-|1
+2026-08-12|3|w|St. Clare|Feria_IV_after_XI_Sunday_after_Pentecost|-|-|1
+2026-08-13|4|g|Feria|Feria_V_after_XI_Sunday_after_Pentecost|Sts. Hippolytus & Cassian|-|1
+2026-08-14|2|w|Vigil of the Assumption|Feria_VI_after_XI_Sunday_after_Pentecost|St. Eusebius|-|1
+2026-08-15|1|w|Assumption of the Blessed Virgin Mary|Saturday_after_XI_Sunday_after_Pentecost|-|-|1
+2026-08-16|2|g|XII Sunday after Pentecost|-|St. Joachim, Father of the Blessed Virgin|-|1
+2026-08-17|3|w|St. Hyacinth|Feria_II_after_XII_Sunday_after_Pentecost|-|-|1
+2026-08-18|4|g|Feria|Feria_III_after_XII_Sunday_after_Pentecost|St. Agapitus|-|1
+2026-08-19|3|w|St. John Eudes|Feria_IV_after_XII_Sunday_after_Pentecost|-|-|1
+2026-08-20|3|w|St. Bernard of Clairvaux|Feria_V_after_XII_Sunday_after_Pentecost|-|-|1
+2026-08-21|3|w|St. Jane Frances de Chantal|Feria_VI_after_XII_Sunday_after_Pentecost|-|-|1
+2026-08-22|2|w|Immaculate Heart of Mary|Saturday_after_XII_Sunday_after_Pentecost|Sts. Timothy, Hippolytus and Symphorianus, Martyrs|-|1
+2026-08-23|2|g|XIII Sunday after Pentecost|-|-|St. Philip Benizi|1
+2026-08-24|2|r|St. Bartholomew|Feria_II_after_XIII_Sunday_after_Pentecost|-|-|1
+2026-08-25|3|w|St. Louis IX|Feria_III_after_XIII_Sunday_after_Pentecost|-|-|1
+2026-08-26|4|g|Feria|Feria_IV_after_XIII_Sunday_after_Pentecost|St. Zephyrinus|-|1
+2026-08-27|3|w|St. Joseph Calasance|Feria_V_after_XIII_Sunday_after_Pentecost|-|-|1
+2026-08-28|3|r|St. Augustine|Feria_VI_after_XIII_Sunday_after_Pentecost|St. Hermes|-|1
+2026-08-29|3|r|Beheading of St. John the Baptist|Saturday_after_XIII_Sunday_after_Pentecost|St. Sabina|-|1
+2026-08-30|2|g|XIV Sunday after Pentecost|-|-|St. Rose of Lima;Sts. Felix and Adauctus|1
+2026-08-31|3|w|St. Raymond Nonnatus|Feria_II_after_XIV_Sunday_after_Pentecost|-|-|1
+2026-09-01|4|g|Feria|Feria_III_after_XIV_Sunday_after_Pentecost|St. Giles;Twelve Holy Brothers, Martyrs|-|1
+2026-09-02|3|w|St. Stephen of Hungary|Feria_IV_after_XIV_Sunday_after_Pentecost|-|-|1
+2026-09-03|3|w|St. Pius X|Feria_V_after_XIV_Sunday_after_Pentecost|-|-|1
+2026-09-04|4|g|Feria|Feria_VI_after_XIV_Sunday_after_Pentecost|-|-|1
+2026-09-05|3|w|St. Lawrence Justinian|Saturday_after_XIV_Sunday_after_Pentecost|-|-|1
+2026-09-06|2|g|XV Sunday after Pentecost|-|-|-|1
+2026-09-07|4|g|Feria|Feria_II_after_XV_Sunday_after_Pentecost|-|-|1
+2026-09-08|2|w|Nativity of the Blessed Virgin Mary|Feria_III_after_XV_Sunday_after_Pentecost|S. Hadriani|-|1
+2026-09-09|4|g|Feria|Feria_IV_after_XV_Sunday_after_Pentecost|St. Gorgonius|-|1
+2026-09-10|3|w|St. Nicholas of Tolentino|Feria_V_after_XV_Sunday_after_Pentecost|-|-|1
+2026-09-11|4|g|Feria|Feria_VI_after_XV_Sunday_after_Pentecost|Sts. Protus & Hyacinth|-|1
+2026-09-12|3|w|Most Holy Name of Mary|Saturday_after_XV_Sunday_after_Pentecost|-|-|1
+2026-09-13|2|g|XVI Sunday after Pentecost|-|-|-|1
+2026-09-14|2|r|Exaltation of the Holy Cross|Feria_II_after_XVI_Sunday_after_Pentecost|-|-|1
+2026-09-15|2|w|Seven Sorrows of the Blessed Virgin Mary|Feria_III_after_XVI_Sunday_after_Pentecost|S. Nicomedes|-|1
+2026-09-16|3|r|Sts. Cornelius & Cyprian|Feria_IV_after_XVI_Sunday_after_Pentecost|Sts. Euphemia, Lucy and Geminianus|-|1
+2026-09-17|4|g|Feria|Feria_V_after_XVI_Sunday_after_Pentecost|Stigmata of St. Francis|-|1
+2026-09-18|3|w|St. Joseph of Cupertino|Feria_VI_after_XVI_Sunday_after_Pentecost|-|-|1
+2026-09-19|3|r|St. Januarius & Companions|Saturday_after_XVI_Sunday_after_Pentecost|-|-|1
+2026-09-20|2|g|XVII Sunday after Pentecost|-|-|Sts. Eustace & Companions|1
+2026-09-21|2|r|St. Matthew|Feria_II_after_XVII_Sunday_after_Pentecost|-|-|1
+2026-09-22|3|w|St. Thomas of Villanova|Feria_III_after_XVII_Sunday_after_Pentecost|St. Maurice and Companions, Martyrs|-|1
+2026-09-23|2|v|Ember Wednesday of September|-|St. Linus|St. Thecla|1
+2026-09-24|4|g|Feria|Feria_V_after_XVII_Sunday_after_Pentecost|Our Lady of Ransom|-|1
+2026-09-25|2|v|Ember Friday of September|-|-|-|1
+2026-09-26|2|v|Ember Saturday of September|-|Sts. Cyprian & Justina|-|1
+2026-09-27|2|g|XVIII Sunday after Pentecost|-|-|Sts. Cosmas & Damian|1
+2026-09-28|3|r|St. Wenceslaus|Feria_II_after_XVIII_Sunday_after_Pentecost|-|-|1
+2026-09-29|1|w|Dedication of St. Michael the Archangel|Feria_III_after_XVIII_Sunday_after_Pentecost|-|-|1
+2026-09-30|3|w|St. Jerome|Feria_IV_after_XVIII_Sunday_after_Pentecost|-|-|1
+2026-10-01|4|g|Feria|Feria_V_after_XVIII_Sunday_after_Pentecost|St. Remigius|-|1
+2026-10-02|3|w|Holy Guardian Angels|Feria_VI_after_XVIII_Sunday_after_Pentecost|-|-|1
+2026-10-03|3|w|St. Theresa of the Infant Jesus|Saturday_after_XVIII_Sunday_after_Pentecost|-|-|1
+2026-10-04|2|g|XIX Sunday after Pentecost|-|-|St. Francis of Assisi|1
+2026-10-05|4|g|Feria|Feria_II_after_XIX_Sunday_after_Pentecost|St. Placid & Companions|-|1
+2026-10-06|3|w|St. Bruno|Feria_III_after_XIX_Sunday_after_Pentecost|-|-|1
+2026-10-07|2|w|Our Lady of the Rosary|Feria_IV_after_XIX_Sunday_after_Pentecost|St. Mark I|-|1
+2026-10-08|3|w|St. Bridget of Sweden|Feria_V_after_XIX_Sunday_after_Pentecost|Ss. Sergio, Baccho, Marcello and Apulejo Martyrs|-|1
+2026-10-09|3|w|St. John Leonardi|Feria_VI_after_XIX_Sunday_after_Pentecost|St. Dionysius and companions|-|1
+2026-10-10|3|w|St. Francis Borgia|Saturday_after_XIX_Sunday_after_Pentecost|-|-|1
+2026-10-11|2|g|XX Sunday after Pentecost|-|Maternity of the Blessed Virgin Mary|-|1
+2026-10-12|4|g|Feria|Feria_II_after_XX_Sunday_after_Pentecost|-|-|1
+2026-10-13|3|w|St. Edward|Feria_III_after_XX_Sunday_after_Pentecost|-|-|1
+2026-10-14|3|r|St. Callistus I|Feria_IV_after_XX_Sunday_after_Pentecost|-|-|1
+2026-10-15|3|w|St. Teresa of Avila|Feria_V_after_XX_Sunday_after_Pentecost|-|-|1
+2026-10-16|3|w|St. Hedwig|Feria_VI_after_XX_Sunday_after_Pentecost|-|-|1
+2026-10-17|3|w|St. Margaret Mary Alacoque|Saturday_after_XX_Sunday_after_Pentecost|-|-|1
+2026-10-18|2|g|XXI Sunday after Pentecost|-|St. Luke the Evangelist|-|1
+2026-10-19|3|w|St. Peter of Alcantara|Feria_II_after_XXI_Sunday_after_Pentecost|-|-|1
+2026-10-20|3|w|St. John Cantius|Feria_III_after_XXI_Sunday_after_Pentecost|-|-|1
+2026-10-21|4|g|Feria|Feria_IV_after_XXI_Sunday_after_Pentecost|St. Hilarion;St. Ursula and Companions|-|1
+2026-10-22|4|g|Feria|Feria_V_after_XXI_Sunday_after_Pentecost|-|-|1
+2026-10-23|3|w|St. Anthony Mary Claret|Feria_VI_after_XXI_Sunday_after_Pentecost|-|-|1
+2026-10-24|3|w|St. Raphael the Archangel|Saturday_after_XXI_Sunday_after_Pentecost|-|-|1
+2026-10-25|1|w|Christ the King|XXII_Sunday_after_Pentecost|-|Sts. Chrysanthus & Daria|1
+2026-10-26|4|g|Feria|Feria_II_after_XXII_Sunday_after_Pentecost|St. Evaristus|-|1
+2026-10-27|4|g|Feria|Feria_III_after_XXII_Sunday_after_Pentecost|-|-|1
+2026-10-28|2|r|Sts. Simon & Jude|Feria_IV_after_XXII_Sunday_after_Pentecost|-|-|1
+2026-10-29|4|g|Feria|Feria_V_after_XXII_Sunday_after_Pentecost|-|-|1
+2026-10-30|4|g|Feria|Feria_VI_after_XXII_Sunday_after_Pentecost|-|-|1
+2026-10-31|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XXII_Sunday_after_Pentecost|-|-|1
+2026-11-01|1|w|All Saints|XXIII_Sunday_after_Pentecost|-|-|1
+2026-11-02|1|b|Commemoration of All Souls|Feria_II_after_XXIII_Sunday_after_Pentecost|-|-|3
+2026-11-03|4|g|Feria|Feria_III_after_XXIII_Sunday_after_Pentecost|-|-|1
+2026-11-04|3|w|St. Charles Borromeo|Feria_IV_after_XXIII_Sunday_after_Pentecost|Sts. Vitalis and Agricola, Martyrs|-|1
+2026-11-05|4|g|Feria|Feria_V_after_XXIII_Sunday_after_Pentecost|-|-|1
+2026-11-06|4|g|Feria|Feria_VI_after_XXIII_Sunday_after_Pentecost|-|-|1
+2026-11-07|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XXIII_Sunday_after_Pentecost|-|-|1
+2026-11-08|2|g|V Sunday after Epiphany|-|-|Four Holy Crowned Martyrs|1
+2026-11-09|2|w|Dedication of the Archbasilica of Our Holy Savior|Feria_II_after_V_Sunday_after_Epiphany|St. Theodore|-|1
+2026-11-10|3|w|St. Andrew Avellino|Feria_III_after_V_Sunday_after_Epiphany|Sts. Tryphonis, Respicii, et Nymphae|-|1
+2026-11-11|3|w|St. Martin of Tours|Feria_IV_after_V_Sunday_after_Epiphany|St. Menna|-|1
+2026-11-12|3|r|St. Martin I|Feria_V_after_V_Sunday_after_Epiphany|-|-|1
+2026-11-13|4|g|Feria|Feria_VI_after_V_Sunday_after_Epiphany|St. Didacus|-|1
+2026-11-14|3|w|St. Josaphat|Saturday_after_V_Sunday_after_Epiphany|-|-|1
+2026-11-15|2|g|VI Sunday after Epiphany|-|-|St. Albert the Great|1
+2026-11-16|3|w|St. Gertrude the Great|Feria_II_after_VI_Sunday_after_Epiphany|-|-|1
+2026-11-17|3|w|St. Gregory the Wonderworker|Feria_III_after_VI_Sunday_after_Epiphany|-|-|1
+2026-11-18|3|w|Dedication of the Basilicas of Sts. Peter & Paul|Feria_IV_after_VI_Sunday_after_Epiphany|-|-|1
+2026-11-19|3|w|St. Elizabeth of Hungary|Feria_V_after_VI_Sunday_after_Epiphany|St. Pontian|-|1
+2026-11-20|3|w|St. Felix of Valois|Feria_VI_after_VI_Sunday_after_Epiphany|-|-|1
+2026-11-21|3|w|Presentation of the Blessed Virgin Mary|Saturday_after_VI_Sunday_after_Epiphany|-|-|1
+2026-11-22|2|g|XXIV Sunday after Pentecost|-|-|St. Cecilia|1
+2026-11-23|3|r|St. Clement I|Feria_II_after_XXIV_Sunday_after_Pentecost|St. Felicity|-|1
+2026-11-24|3|w|St. John of the Cross|Feria_III_after_XXIV_Sunday_after_Pentecost|St. Chrysogonus|-|1
+2026-11-25|3|r|St. Catherine of Alexandria|Feria_IV_after_XXIV_Sunday_after_Pentecost|-|-|1
+2026-11-26|3|w|St. Sylvester|Feria_V_after_XXIV_Sunday_after_Pentecost|St. Peter of Alexandria|-|1
+2026-11-27|4|g|Feria|Feria_VI_after_XXIV_Sunday_after_Pentecost|-|-|1
+2026-11-28|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XXIV_Sunday_after_Pentecost|-|-|1
+2026-11-29|1|v|I Sunday of Advent|-|-|St. Saturninus|1
+2026-11-30|2|r|St. Andrew|Feria_II_after_I_Sunday_of_Advent|-|-|1
+2026-12-01|3|v|Feria III after I Sunday of Advent|-|-|-|1
+2026-12-02|3|r|St. Vivian|Feria_IV_after_I_Sunday_of_Advent|Feria IV after I Sunday of Advent|-|1
+2026-12-03|3|w|St. Francis Xavier|Feria_V_after_I_Sunday_of_Advent|Feria V after I Sunday of Advent|-|1
+2026-12-04|3|w|St. Peter Chrysologus|Feria_VI_after_I_Sunday_of_Advent|Feria VI after I Sunday of Advent|-|1
+2026-12-05|3|v|Sabbato after I Sunday of Advent|-|St. Sabbas|-|1
+2026-12-06|1|v|II Sunday of Advent|-|-|St. Nicholas|1
+2026-12-07|3|w|St. Ambrose|Feria_II_after_II_Sunday_of_Advent|Feria II after II Sunday of Advent|-|1
+2026-12-08|1|w|Immaculate Conception of the Blessed Virgin Mary|Feria_III_after_II_Sunday_of_Advent|-|-|1
+2026-12-09|3|v|Feria IV after II Sunday of Advent|-|-|-|1
+2026-12-10|3|v|Feria V after II Sunday of Advent|-|St. Melchiades|-|1
+2026-12-11|3|w|St. Damasus I|Feria_VI_after_II_Sunday_of_Advent|Feria VI after II Sunday of Advent|-|1
+2026-12-12|3|v|Sabbato after II Sunday of Advent|-|-|-|1
+2026-12-13|1|pv|III Sunday of Advent|-|-|St. Lucy|1
+2026-12-14|3|pv|Feria II after III Sunday of Advent|-|-|-|1
+2026-12-15|3|pv|Feria III after III Sunday of Advent|-|-|-|1
+2026-12-16|2|v|Ember Wednesday of Advent|-|St. Eusebius|-|1
+2026-12-17|2|pv|Feria V after III Sunday of Advent|-|-|-|1
+2026-12-18|2|v|Ember Friday of Advent|-|-|-|1
+2026-12-19|2|v|Ember Saturday of Advent|-|-|-|1
+2026-12-20|1|v|IV Sunday of Advent|-|-|-|1
+2026-12-21|2|r|St. Thomas|Feria_II_after_IV_Sunday_of_Advent|Feria II after IV Sunday of Advent|-|1
+2026-12-22|2|v|Feria III after IV Sunday of Advent|-|-|-|1
+2026-12-23|2|v|Feria IV after IV Sunday of Advent|-|-|-|1
+2026-12-24|1|v|Vigil of Christmas|-|-|-|1
+2026-12-25|1|w|The Nativity of Our Lord|-|-|-|3
+2026-12-26|2|r|St. Stephen|-|For Octave of the Nativity|-|1
+2026-12-27|2|w|Sunday in the Octave of Christmas|-|St. John the Evangelist|For Octave of the Nativity|1
+2026-12-28|2|r|Holy Innocents|-|For Octave of the Nativity|-|1
+2026-12-29|2|w|Feria in the Octave of Christmas|-|St. Thomas Becket|-|1
+2026-12-30|2|w|Feria in the Octave of Christmas|-|-|-|1
+2026-12-31|2|w|Feria in the Octave of Christmas|-|St. Silvester|-|1
+2027-01-01|1|w|Octave Day of Christmas|-|-|-|1
+2027-01-02|4|w|II Mass of the B. V. M. – Vultum Tuum|-|-|-|1
+2027-01-03|2|w|Holy Name of Jesus|-|-|-|1
+2027-01-04|4|w|Feria|-|-|-|1
+2027-01-05|4|w|Feria|-|St. Telesphorus Pope and Martyr|-|1
+2027-01-06|1|w|Epiphany of the Lord|-|-|-|1
+2027-01-07|4|w|Feria|-|-|-|1
+2027-01-08|4|w|Feria|-|-|-|1
+2027-01-09|4|w|II Mass of the B. V. M. – Vultum Tuum|-|-|-|1
+2027-01-10|2|w|The Holy Family: Jesus, Mary & Joseph|-|-|-|1
+2027-01-11|4|w|Feria|Feria_II_after_Epiphany|St. Hyginus Pope and Martyr|-|1
+2027-01-12|4|w|Feria|Feria_III_after_Epiphany|-|-|1
+2027-01-13|2|w|Commemoration of the Baptism of the Lord|Feria_IV_after_Epiphany|-|-|1
+2027-01-14|3|w|St. Hilary|Feria_V_after_Epiphany|S. Felicis|-|1
+2027-01-15|3|w|St. Paul, the First Hermit|Feria_VI_after_Epiphany|St. Maur, Abbot|-|1
+2027-01-16|3|r|St. Marcellus I|Saturday_after_Epiphany|-|-|1
+2027-01-17|2|g|II Sunday after Epiphany|-|-|St. Anthony|1
+2027-01-18|4|g|Feria|Feria_II_after_II_Sunday_after_Epiphany|St. Prisca|-|1
+2027-01-19|4|g|Feria|Feria_III_after_II_Sunday_after_Epiphany|Sts. Marius, Martha, Audifax & Abachum;St. Canute, Martyr|-|1
+2027-01-20|3|r|Sts. Fabian & Sebastian|Feria_IV_after_II_Sunday_after_Epiphany|-|-|1
+2027-01-21|3|r|St. Agnes|Feria_V_after_II_Sunday_after_Epiphany|-|-|1
+2027-01-22|3|r|Sts. Vincent & Anastasius|Feria_VI_after_II_Sunday_after_Epiphany|-|-|1
+2027-01-23|3|w|St. Raymond of Peñafort|Saturday_after_II_Sunday_after_Epiphany|St. Emerentiana|-|1
+2027-01-24|2|v|Septuagesima Sunday|-|-|St. Timothy|1
+2027-01-25|3|w|Conversion of St. Paul|Feria_II_after_Septuagesima|St. Peter|-|1
+2027-01-26|3|r|St. Polycarp|Feria_III_after_Septuagesima|-|-|1
+2027-01-27|3|w|St. John Chrysostom|Feria_IV_after_Septuagesima|-|-|1
+2027-01-28|3|w|St. Peter Nolasco|Feria_V_after_Septuagesima|St. Agnes|-|1
+2027-01-29|3|w|St. Francis de Sales|Feria_VI_after_Septuagesima|-|-|1
+2027-01-30|3|r|St. Martina|Saturday_after_Septuagesima|-|-|1
+2027-01-31|2|v|Sexagesima Sunday|-|-|St. John Bosco|1
+2027-02-01|3|r|St. Ignatius of Antioch|Feria_II_after_Sexagesima|-|-|1
+2027-02-02|2|w|Purification of the Blessed Virgin Mary|Feria_III_after_Sexagesimæ|-|-|1
+2027-02-03|4|v|Feria|Feria_IV_after_Sexagesimæ|St. Blaise|-|1
+2027-02-04|3|w|St. Andrew Corsini|Feria_V_after_Sexagesimæ|-|-|1
+2027-02-05|3|r|St. Agatha|Feria_VI_after_Sexagesimæ|-|-|1
+2027-02-06|3|w|St. Titus|Saturday_after_Sexagesimæ|St. Dorothy|-|1
+2027-02-07|2|v|Quinquagesima Sunday|-|-|St. Romuald|1
+2027-02-08|3|w|St. John of Matha|Feria_II_after_Quinquagesima|-|-|1
+2027-02-09|3|w|St. Cyril of Alexandria|Feria_III_after_Quinquagesima|St. Appollonia|-|1
+2027-02-10|1|v|Ash Wednesday|-|-|St. Scholastica|1
+2027-02-11|3|v|Feria V after Ash Wednesday|-|Our Lady of Lourdes|-|1
+2027-02-12|3|v|Feria VI after Ash Wednesday|-|Seven Holy Servite Founders|-|1
+2027-02-13|3|v|Saturday after Ash Wednesday|-|-|-|1
+2027-02-14|1|v|I Sunday of Lent|-|-|St. Valentine|1
+2027-02-15|3|v|Feria II after the I Sunday of Lent|-|Sts. Faustinus & Jovita|-|1
+2027-02-16|3|v|Feria III after the I Sunday of Lent|-|-|-|1
+2027-02-17|2|v|Ember Wednesday of Lent|-|-|-|1
+2027-02-18|3|v|Feria V after the I Sunday of Lent|-|St. Simeon|-|1
+2027-02-19|2|v|Ember Friday of Lent|-|-|-|1
+2027-02-20|2|v|Ember Saturday of Lent|-|-|-|1
+2027-02-21|1|v|II Sunday of Lent|-|-|-|1
+2027-02-22|2|w|Chair of St. Peter|Feria_II_after_the_II_Sunday_of_Lent|St. Paul;Feria II after the II Sunday of Lent|-|1
+2027-02-23|3|v|Feria III after the II Sunday of Lent|-|St. Peter Damien|-|1
+2027-02-24|2|r|St. Matthias|Feria_IV_after_the_II_Sunday_of_Lent|Feria IV after the II Sunday of Lent|-|1
+2027-02-25|3|v|Feria V after the II Sunday of Lent|-|-|-|1
+2027-02-26|3|v|Feria VI after the II Sunday of Lent|-|-|-|1
+2027-02-27|3|v|Saturday after the II Sunday of Lent|-|St. Gabriel of Our Lady of Sorrows|-|1
+2027-02-28|1|v|III Sunday of Lent|-|-|-|1
+2027-03-01|3|v|Feria II after the III Sunday of Lent|-|-|-|1
+2027-03-02|3|v|Feria III after the III Sunday of Lent|-|-|-|1
+2027-03-03|3|v|Feria IV after the III Sunday of Lent|-|-|-|1
+2027-03-04|3|v|Feria V after the III Sunday of Lent|-|St. Casimir;St. Lucius|-|1
+2027-03-05|3|v|Feria VI after the III Sunday of Lent|-|-|-|1
+2027-03-06|3|v|Saturday after the III Sunday of Lent|-|Sts. Felicitas & Perpetua|-|1
+2027-03-07|1|pv|IV Sunday of Lent|-|-|St. Thomas Aquinas|1
+2027-03-08|3|v|Feria II after the IV Sunday of Lent|-|St. John of God|-|1
+2027-03-09|3|v|Feria III after the IV Sunday of Lent|-|St. Frances Rome|-|1
+2027-03-10|3|v|Feria IV after the IV Sunday of Lent|-|Forty Holy Martyrs of Sebaste|-|1
+2027-03-11|3|v|Feria V after the IV Sunday of Lent|-|-|-|1
+2027-03-12|3|v|Feria VI after the IV Sunday of Lent|-|St. Gregory the Great|-|1
+2027-03-13|3|v|Saturday after the IV Sunday of Lent|-|-|-|1
+2027-03-14|1|v|Passion Sunday|-|-|-|1
+2027-03-15|3|v|Feria II of Passion Week|-|-|-|1
+2027-03-16|3|v|Feria III of Passion Week|-|-|-|1
+2027-03-17|3|v|Feria IV of Passion Week|-|St. Patrick|-|1
+2027-03-18|3|v|Feria V of Passion Week|-|St. Cyril of Jerusalem|-|1
+2027-03-19|3|v|Feria VI of Passion Week|-|For Our Lady of the Seven Sorrows|St. Joseph, Spouse of the Bl. Virgin Mary|1
+2027-03-20|3|v|Saturday of Passion Week|-|-|-|1
+2027-03-21|1|rv|Palm Sunday|-|-|St. Benedict|1
+2027-03-22|1|v|Feria II of Holy Week|-|-|-|1
+2027-03-23|1|v|Feria III of Holy Week|-|-|-|1
+2027-03-24|1|v|Feria IV of Holy Week|-|-|St. Gabriel the Archangel|1
+2027-03-25|1|w|Holy Thursday|-|-|Annunciation of the Blessed Virgin Mary|1
+2027-03-26|1|bv|Good Friday|-|-|-|1
+2027-03-27|1|vw|Holy Saturday|-|-|St. John Damascene|1
+2027-03-28|1|w|Easter Sunday|-|-|St. John of Capistrano|1
+2027-03-29|1|w|Monday in the Octave of Easter|-|-|-|1
+2027-03-30|1|w|Tuesday in the Octave of Easter|-|-|-|1
+2027-03-31|1|w|Wednesday in the Octave of Easter|-|-|-|1
+2027-04-01|1|w|Thursday in the Octave of Easter|-|-|-|1
+2027-04-02|1|w|Friday in the Octave of Easter|-|-|St. Francis of Paola|1
+2027-04-03|1|w|Saturday in the Octave of Easter|-|-|-|1
+2027-04-04|1|w|Low Sunday|-|-|St. Isidore of Seville|1
+2027-04-05|1|w|Annunciation of the Blessed Virgin Mary|Monday_after_I_Sunday_after_Easter|-|St. Vincent Ferrer|1
+2027-04-06|4|w|Feria|Tuesday_after_I_Sunday_after_Easter|-|-|1
+2027-04-07|4|w|Feria|Wednesday_after_I_Sunday_after_Easter|-|-|1
+2027-04-08|4|w|Feria|Thursday_after_I_Sunday_after_Easter|-|-|1
+2027-04-09|4|w|Feria|Friday_after_I_Sunday_after_Easter|-|-|1
+2027-04-10|4|w|IV Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_I_Sunday_after_Easter|-|-|1
+2027-04-11|2|w|II Sunday after Easter|-|-|St. Leo the Great|1
+2027-04-12|4|w|Feria|Monday_after_II_Sunday_after_Easter|-|-|1
+2027-04-13|3|r|St. Hermenegild|Tuesday_after_II_Sunday_after_Easter|-|-|1
+2027-04-14|3|r|St. Justin|Wednesday_after_II_Sunday_after_Easter|Sts. Tiburtius, Valerian et Maximus, Martyrs|-|1
+2027-04-15|4|w|Feria|Thursday_after_II_Sunday_after_Easter|-|-|1
+2027-04-16|4|w|Feria|Friday_after_II_Sunday_after_Easter|-|-|1
+2027-04-17|4|w|IV Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_II_Sunday_after_Easter|St. Anicetus|-|1
+2027-04-18|2|w|III Sunday after Easter|-|-|-|1
+2027-04-19|4|w|Feria|Monday_after_III_Sunday_after_Easter|-|-|1
+2027-04-20|4|w|Feria|Tuesday_after_III_Sunday_after_Easter|-|-|1
+2027-04-21|3|w|St. Anselm|Wednesday_after_III_Sunday_after_Easter|-|-|1
+2027-04-22|3|r|Sts. Soter & Caius|Thursday_after_III_Sunday_after_Easter|-|-|1
+2027-04-23|4|w|Feria|Friday_after_III_Sunday_after_Easter|St. George|-|1
+2027-04-24|3|r|St. Fidelis of Sigmaringen|Saturday_after_III_Sunday_after_Easter|-|-|1
+2027-04-25|2|w|IV Sunday after Easter|-|St. Mark|Pro rogationibus|1
+2027-04-26|3|r|Sts. Cletus & Marcellinus|Monday_after_IV_Sunday_after_Easter|-|-|1
+2027-04-27|3|w|St. Peter Canisius|Tuesday_after_IV_Sunday_after_Easter|-|-|1
+2027-04-28|3|w|St. Paul of the Cross|Wednesday_after_IV_Sunday_after_Easter|-|-|1
+2027-04-29|3|r|St. Peter of Verona|Thursday_after_IV_Sunday_after_Easter|-|-|1
+2027-04-30|3|w|St. Catherine of Siena|Friday_after_IV_Sunday_after_Easter|-|-|1
+2027-05-01|1|w|St. Joseph the Workman|Saturday_after_IV_Sunday_after_Easter|-|-|1
+2027-05-02|2|w|V Sunday after Easter|-|-|St. Athanasius|1
+2027-05-03|4|w|Feria|The_Minor_Litanies_–_Rogations|Sts. Alexander & Companions|-|1
+2027-05-04|3|w|St. Monica|The_Minor_Litanies_–_Rogations|-|-|1
+2027-05-05|2|w|Vigil of the Ascension|-|St. Pius V|-|1
+2027-05-06|1|w|Ascension of the Lord|-|-|-|1
+2027-05-07|3|r|St. Stanislaus|Feria_VI_after_the_Ascension|-|-|1
+2027-05-08|4|w|IV Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_the_Ascension|-|-|1
+2027-05-09|2|w|Sunday after the Ascension|-|-|St. Gregory of Nazianzen|1
+2027-05-10|3|w|St. Antoninus|Feria_II_after_the_Ascension|St. Gordiano and Epimacho|-|1
+2027-05-11|2|r|Sts. Philip & James|Feria_III_after_the_Ascension|-|-|1
+2027-05-12|3|r|Sts. Nereus, Achilleus, Domitilla, & Pancras|Feria_IV_after_the_Ascension|-|-|1
+2027-05-13|3|w|St. Robert Bellarmine|Feria_V_after_the_Ascension|-|-|1
+2027-05-14|4|w|Feria|Feria_VI_after_the_Ascension|St. Boniface|-|1
+2027-05-15|1|r|Saturday after the Ascension|-|-|St. John Baptist de la Salle|1
+2027-05-16|1|r|Pentecost Sunday|-|-|St. Ubaldus|1
+2027-05-17|1|r|Monday after Pentecost|-|-|St. Paschal Baylon|1
+2027-05-18|1|r|Tuesday after Pentecost|-|-|St. Venantius|1
+2027-05-19|1|r|Ember Wednesday of Pentecost|-|-|St. Peter Celestine;St. Pudentiana Virginis|1
+2027-05-20|1|r|Thursday after Pentecost|-|-|St. Bernardine of Siena|1
+2027-05-21|1|r|Ember Friday of Pentecost|-|-|-|1
+2027-05-22|1|r|Ember Saturday of Pentecost|-|-|-|1
+2027-05-23|1|w|Trinity Sunday|-|-|-|1
+2027-05-24|4|g|Feria|Feria_II_after_I_Sunday_after_Pentecost|-|-|1
+2027-05-25|3|w|St. Gregory VII|Feria_III_after_I_Sunday_after_Pentecost|St. Urban, Pope and Martyr|-|1
+2027-05-26|3|w|St. Philip Neri|Feria_IV_after_I_Sunday_after_Pentecost|S. Eleutherius|-|1
+2027-05-27|1|w|Corpus Christi|-|-|St. Bede the Venerable;St. John I|1
+2027-05-28|3|w|St. Augustine of Canterbury|Feria_V_after_I_Sunday_after_Pentecost|-|-|1
+2027-05-29|3|w|St. Mary Magdalene de Pazzi|Saturday_after_I_Sunday_after_Pentecost|-|-|1
+2027-05-30|2|g|II Sunday after Pentecost|-|-|St. Felix I|1
+2027-05-31|2|w|Queenship of the Blessed Virgin Mary|Feria_II_after_II_Sunday_after_Pentecost|St. Petronilla|-|1
+2027-06-01|3|w|St. Angela Merici|Feria_III_after_II_Sunday_after_Pentecost|-|-|1
+2027-06-02|4|g|Feria|Feria_IV_after_II_Sunday_after_Pentecost|Sts. Marcellinus, Peter, & Erasmus|-|1
+2027-06-03|4|g|Feria|Feria_V_after_II_Sunday_after_Pentecost|-|-|1
+2027-06-04|1|w|Sacred Heart of Jesus|-|-|St. Francis Caracciolo|1
+2027-06-05|3|r|St. Boniface|Saturday_after_II_Sunday_after_Pentecost|-|-|1
+2027-06-06|2|g|III Sunday after Pentecost|-|-|St. Norbert|1
+2027-06-07|4|g|Feria|Feria_II_after_III_Sunday_after_Pentecost|-|-|1
+2027-06-08|4|g|Feria|Feria_III_after_III_Sunday_after_Pentecost|-|-|1
+2027-06-09|4|g|Feria|Feria_IV_after_III_Sunday_after_Pentecost|Sts. Primus & Felicianus|-|1
+2027-06-10|3|w|St. Margaret of Scotland|Feria_V_after_III_Sunday_after_Pentecost|-|-|1
+2027-06-11|3|r|St. Barnabas|Feria_VI_after_III_Sunday_after_Pentecost|-|-|1
+2027-06-12|3|r|St. John of San Fecundo|Saturday_after_III_Sunday_after_Pentecost|St. Basilidus|-|1
+2027-06-13|2|g|IV Sunday after Pentecost|-|-|St. Anthony of Padua|1
+2027-06-14|3|w|St. Basil the Great|Feria_II_after_IV_Sunday_after_Pentecost|-|-|1
+2027-06-15|4|g|Feria|Feria_III_after_IV_Sunday_after_Pentecost|St. Vitus|-|1
+2027-06-16|4|g|Feria|Feria_IV_after_IV_Sunday_after_Pentecost|-|-|1
+2027-06-17|3|w|St. Gregory Barbarigo|Feria_V_after_IV_Sunday_after_Pentecost|-|-|1
+2027-06-18|3|r|St. Ephrem of Syria|Feria_VI_after_IV_Sunday_after_Pentecost|Ss. Marcus and Marcellianus|-|1
+2027-06-19|3|r|St. Julia of Falconieri|Saturday_after_IV_Sunday_after_Pentecost|Sts. Gervasius and Protasius|-|1
+2027-06-20|2|g|V Sunday after Pentecost|-|-|St. Silverius|1
+2027-06-21|3|w|St. Aloysius Gongzaga|Feria_II_after_V_Sunday_after_Pentecost|-|-|1
+2027-06-22|3|w|St. Paulinus of Nola|Feria_III_after_V_Sunday_after_Pentecost|-|-|1
+2027-06-23|2|v|Vigil of the Nativity of St. John the Baptist|Feria_IV_after_V_Sunday_after_Pentecost|-|-|1
+2027-06-24|1|w|Nativity of St. John the Baptist|Feria_V_after_V_Sunday_after_Pentecost|-|-|1
+2027-06-25|3|w|St. William|Feria_VI_after_V_Sunday_after_Pentecost|-|-|1
+2027-06-26|3|r|Sts. John & Paul|Saturday_after_V_Sunday_after_Pentecost|-|-|1
+2027-06-27|2|g|VI Sunday after Pentecost|-|-|-|1
+2027-06-28|2|v|Vigil of Sts. Peter & Paul|Feria_II_after_VI_Sunday_after_Pentecost|-|-|1
+2027-06-29|1|r|Sts. Peter & Paul|Feria_III_after_VI_Sunday_after_Pentecost|-|-|1
+2027-06-30|3|r|In Commemoratione Sancti Pauli Apostoli|Feria_IV_after_VI_Sunday_after_Pentecost|-|-|1
+2027-07-01|1|r|The Precious Blood of Our Lord Jesus Christ|Feria_V_after_VI_Sunday_after_Pentecost|-|-|1
+2027-07-02|2|w|Visitation of the Blessed Virgin Mary|Feria_VI_after_VI_Sunday_after_Pentecost|SS. Processus and Martinian|-|1
+2027-07-03|3|r|St. Irenaeus|Saturday_after_VI_Sunday_after_Pentecost|-|-|1
+2027-07-04|2|g|VII Sunday after Pentecost|-|-|-|1
+2027-07-05|3|w|St. Anthony Mary Zaccariah|Feria_II_after_VII_Sunday_after_Pentecost|-|-|1
+2027-07-06|4|g|Feria|Feria_III_after_VII_Sunday_after_Pentecost|-|-|1
+2027-07-07|3|w|Sts. Cyril & Methodius|Feria_IV_after_VII_Sunday_after_Pentecost|-|-|1
+2027-07-08|3|w|St. Elizabeth of Portugal|Feria_V_after_VII_Sunday_after_Pentecost|-|-|1
+2027-07-09|4|g|Feria|Feria_VI_after_VII_Sunday_after_Pentecost|-|-|1
+2027-07-10|3|r|Seven Holy Brothers and Sts. Rufina & Secunda|Saturday_after_VII_Sunday_after_Pentecost|-|-|1
+2027-07-11|2|g|VIII Sunday after Pentecost|-|-|St. Pius I|1
+2027-07-12|3|r|St. John Gualbert|Feria_II_after_VIII_Sunday_after_Pentecost|Ss. Naboris et Felicis|-|1
+2027-07-13|4|g|Feria|Feria_III_after_VIII_Sunday_after_Pentecost|-|-|1
+2027-07-14|3|w|St. Bonaventure|Feria_IV_after_VIII_Sunday_after_Pentecost|-|-|1
+2027-07-15|3|w|St. Henry the Emperor|Feria_V_after_VIII_Sunday_after_Pentecost|-|-|1
+2027-07-16|4|g|Feria|Feria_VI_after_VIII_Sunday_after_Pentecost|Our Lady of Mt. Carmel|-|1
+2027-07-17|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_VIII_Sunday_after_Pentecost|St. Alexis|-|1
+2027-07-18|2|g|IX Sunday after Pentecost|-|-|Camillus de Lellis;Ss. Symphorosa and sons|1
+2027-07-19|3|w|St. Vincent de Paul|Feria_II_after_IX_Sunday_after_Pentecost|-|-|1
+2027-07-20|3|r|St. Jerome Emiliani|Feria_III_after_IX_Sunday_after_Pentecost|St. Margaret|-|1
+2027-07-21|3|w|St. Laurence of Brindisi|Feria_IV_after_IX_Sunday_after_Pentecost|St. Praxedis Virginis|-|1
+2027-07-22|3|w|St. Mary Magdalene|Feria_V_after_IX_Sunday_after_Pentecost|-|-|1
+2027-07-23|3|w|St. Apollinaris|Feria_VI_after_IX_Sunday_after_Pentecost|S. Liborii|-|1
+2027-07-24|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_IX_Sunday_after_Pentecost|St. Christina|-|1
+2027-07-25|2|g|X Sunday after Pentecost|-|St. James the Greater|St. Christopher|1
+2027-07-26|2|w|St. Anne, Mother of the Blessed Virgin|Feria_II_after_X_Sunday_after_Pentecost|-|-|1
+2027-07-27|4|g|Feria|Feria_III_after_X_Sunday_after_Pentecost|St. Pantaleon|-|1
+2027-07-28|3|r|Sts. Nazarius & Celsus, St. Victor I & St. Innocent I|Feria_IV_after_X_Sunday_after_Pentecost|-|-|1
+2027-07-29|3|r|St. Martha|Feria_V_after_X_Sunday_after_Pentecost|Ss. Felicis, Simplicii, Faustini et Beatricis|-|1
+2027-07-30|4|g|Feria|Feria_VI_after_X_Sunday_after_Pentecost|Sts. Abdon & Sennen|-|1
+2027-07-31|3|w|St. Ignatius Loyola|Saturday_after_X_Sunday_after_Pentecost|-|-|1
+2027-08-01|2|g|XI Sunday after Pentecost|-|-|Holy Machabees|1
+2027-08-02|3|r|St. Alphonsus Liguori|Feria_II_after_XI_Sunday_after_Pentecost|St. Stephen I, Pope and Martyr|-|1
+2027-08-03|4|g|Feria|Feria_III_after_XI_Sunday_after_Pentecost|-|-|1
+2027-08-04|3|w|St. Dominic|Feria_IV_after_XI_Sunday_after_Pentecost|-|-|1
+2027-08-05|3|w|Dedication of the Basilica of St. Mary Major|Feria_V_after_XI_Sunday_after_Pentecost|-|-|1
+2027-08-06|2|w|Transfiguration of Our Lord|Feria_VI_after_XI_Sunday_after_Pentecost|Pope Sixtus II, Felicissimus and Agapitus, Martyrs|-|1
+2027-08-07|3|w|St. Cajetan|Saturday_after_XI_Sunday_after_Pentecost|St. Donatus|-|1
+2027-08-08|2|g|XII Sunday after Pentecost|-|-|St. John Mary Vianney;Ss. Cyriacus, Largus and Smaragdus, Martyrs|1
+2027-08-09|3|r|Vigil of St. Lawrence|Feria_II_after_XII_Sunday_after_Pentecost|St. Romanus|-|1
+2027-08-10|2|r|St. Lawrence|Feria_III_after_XII_Sunday_after_Pentecost|-|-|1
+2027-08-11|4|g|Feria|Feria_IV_after_XII_Sunday_after_Pentecost|Sts. Tiburtius & Susanna|-|1
+2027-08-12|3|w|St. Clare|Feria_V_after_XII_Sunday_after_Pentecost|-|-|1
+2027-08-13|4|g|Feria|Feria_VI_after_XII_Sunday_after_Pentecost|Sts. Hippolytus & Cassian|-|1
+2027-08-14|2|w|Vigil of the Assumption|Saturday_after_XII_Sunday_after_Pentecost|St. Eusebius|-|1
+2027-08-15|1|w|Assumption of the Blessed Virgin Mary|XIII_Sunday_after_Pentecost|-|-|1
+2027-08-16|2|w|St. Joachim, Father of the Blessed Virgin|Feria_II_after_XIII_Sunday_after_Pentecost|-|-|1
+2027-08-17|3|w|St. Hyacinth|Feria_III_after_XIII_Sunday_after_Pentecost|-|-|1
+2027-08-18|4|g|Feria|Feria_IV_after_XIII_Sunday_after_Pentecost|St. Agapitus|-|1
+2027-08-19|3|w|St. John Eudes|Feria_V_after_XIII_Sunday_after_Pentecost|-|-|1
+2027-08-20|3|w|St. Bernard of Clairvaux|Feria_VI_after_XIII_Sunday_after_Pentecost|-|-|1
+2027-08-21|3|w|St. Jane Frances de Chantal|Saturday_after_XIII_Sunday_after_Pentecost|-|-|1
+2027-08-22|2|g|XIV Sunday after Pentecost|-|Immaculate Heart of Mary|Sts. Timothy, Hippolytus and Symphorianus, Martyrs|1
+2027-08-23|3|w|St. Philip Benizi|Feria_II_after_XIV_Sunday_after_Pentecost|-|-|1
+2027-08-24|2|r|St. Bartholomew|Feria_III_after_XIV_Sunday_after_Pentecost|-|-|1
+2027-08-25|3|w|St. Louis IX|Feria_IV_after_XIV_Sunday_after_Pentecost|-|-|1
+2027-08-26|4|g|Feria|Feria_V_after_XIV_Sunday_after_Pentecost|St. Zephyrinus|-|1
+2027-08-27|3|w|St. Joseph Calasance|Feria_VI_after_XIV_Sunday_after_Pentecost|-|-|1
+2027-08-28|3|r|St. Augustine|Saturday_after_XIV_Sunday_after_Pentecost|St. Hermes|-|1
+2027-08-29|2|g|XV Sunday after Pentecost|-|-|Beheading of St. John the Baptist;St. Sabina|1
+2027-08-30|3|r|St. Rose of Lima|Feria_II_after_XV_Sunday_after_Pentecost|Sts. Felix and Adauctus|-|1
+2027-08-31|3|w|St. Raymond Nonnatus|Feria_III_after_XV_Sunday_after_Pentecost|-|-|1
+2027-09-01|4|g|Feria|Feria_IV_after_XV_Sunday_after_Pentecost|St. Giles;Twelve Holy Brothers, Martyrs|-|1
+2027-09-02|3|w|St. Stephen of Hungary|Feria_V_after_XV_Sunday_after_Pentecost|-|-|1
+2027-09-03|3|w|St. Pius X|Feria_VI_after_XV_Sunday_after_Pentecost|-|-|1
+2027-09-04|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XV_Sunday_after_Pentecost|-|-|1
+2027-09-05|2|g|XVI Sunday after Pentecost|-|-|St. Lawrence Justinian|1
+2027-09-06|4|g|Feria|Feria_II_after_XVI_Sunday_after_Pentecost|-|-|1
+2027-09-07|4|g|Feria|Feria_III_after_XVI_Sunday_after_Pentecost|-|-|1
+2027-09-08|2|w|Nativity of the Blessed Virgin Mary|Feria_IV_after_XVI_Sunday_after_Pentecost|S. Hadriani|-|1
+2027-09-09|4|g|Feria|Feria_V_after_XVI_Sunday_after_Pentecost|St. Gorgonius|-|1
+2027-09-10|3|w|St. Nicholas of Tolentino|Feria_VI_after_XVI_Sunday_after_Pentecost|-|-|1
+2027-09-11|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XVI_Sunday_after_Pentecost|Sts. Protus & Hyacinth|-|1
+2027-09-12|2|g|XVII Sunday after Pentecost|-|-|Most Holy Name of Mary|1
+2027-09-13|4|g|Feria|Feria_II_after_XVII_Sunday_after_Pentecost|-|-|1
+2027-09-14|2|r|Exaltation of the Holy Cross|Feria_III_after_XVII_Sunday_after_Pentecost|-|-|1
+2027-09-15|2|w|Seven Sorrows of the Blessed Virgin Mary|Feria_IV_after_XVII_Sunday_after_Pentecost|S. Nicomedes|-|1
+2027-09-16|3|r|Sts. Cornelius & Cyprian|Feria_V_after_XVII_Sunday_after_Pentecost|Sts. Euphemia, Lucy and Geminianus|-|1
+2027-09-17|4|g|Feria|Feria_VI_after_XVII_Sunday_after_Pentecost|Stigmata of St. Francis|-|1
+2027-09-18|3|w|St. Joseph of Cupertino|Saturday_after_XVII_Sunday_after_Pentecost|-|-|1
+2027-09-19|2|g|XVIII Sunday after Pentecost|-|-|St. Januarius & Companions|1
+2027-09-20|4|g|Feria|Feria_II_after_XVIII_Sunday_after_Pentecost|Sts. Eustace & Companions|-|1
+2027-09-21|2|r|St. Matthew|Feria_III_after_XVIII_Sunday_after_Pentecost|-|-|1
+2027-09-22|2|v|Ember Wednesday of September|-|St. Thomas of Villanova|St. Maurice and Companions, Martyrs|1
+2027-09-23|3|r|St. Linus|Feria_V_after_XVIII_Sunday_after_Pentecost|St. Thecla|-|1
+2027-09-24|2|v|Ember Friday of September|-|Our Lady of Ransom|-|1
+2027-09-25|2|v|Ember Saturday of September|-|-|-|1
+2027-09-26|2|g|XIX Sunday after Pentecost|-|-|Sts. Cyprian & Justina|1
+2027-09-27|3|r|Sts. Cosmas & Damian|Feria_II_after_XIX_Sunday_after_Pentecost|-|-|1
+2027-09-28|3|r|St. Wenceslaus|Feria_III_after_XIX_Sunday_after_Pentecost|-|-|1
+2027-09-29|1|w|Dedication of St. Michael the Archangel|Feria_IV_after_XIX_Sunday_after_Pentecost|-|-|1
+2027-09-30|3|w|St. Jerome|Feria_V_after_XIX_Sunday_after_Pentecost|-|-|1
+2027-10-01|4|g|Feria|Feria_VI_after_XIX_Sunday_after_Pentecost|St. Remigius|-|1
+2027-10-02|3|w|Holy Guardian Angels|Saturday_after_XIX_Sunday_after_Pentecost|-|-|1
+2027-10-03|2|g|XX Sunday after Pentecost|-|-|St. Theresa of the Infant Jesus|1
+2027-10-04|3|w|St. Francis of Assisi|Feria_II_after_XX_Sunday_after_Pentecost|-|-|1
+2027-10-05|4|g|Feria|Feria_III_after_XX_Sunday_after_Pentecost|St. Placid & Companions|-|1
+2027-10-06|3|w|St. Bruno|Feria_IV_after_XX_Sunday_after_Pentecost|-|-|1
+2027-10-07|2|w|Our Lady of the Rosary|Feria_V_after_XX_Sunday_after_Pentecost|St. Mark I|-|1
+2027-10-08|3|w|St. Bridget of Sweden|Feria_VI_after_XX_Sunday_after_Pentecost|Ss. Sergio, Baccho, Marcello and Apulejo Martyrs|-|1
+2027-10-09|3|w|St. John Leonardi|Saturday_after_XX_Sunday_after_Pentecost|St. Dionysius and companions|-|1
+2027-10-10|2|g|XXI Sunday after Pentecost|-|-|St. Francis Borgia|1
+2027-10-11|2|w|Maternity of the Blessed Virgin Mary|Feria_II_after_XXI_Sunday_after_Pentecost|-|-|1
+2027-10-12|4|g|Feria|Feria_III_after_XXI_Sunday_after_Pentecost|-|-|1
+2027-10-13|3|w|St. Edward|Feria_IV_after_XXI_Sunday_after_Pentecost|-|-|1
+2027-10-14|3|r|St. Callistus I|Feria_V_after_XXI_Sunday_after_Pentecost|-|-|1
+2027-10-15|3|w|St. Teresa of Avila|Feria_VI_after_XXI_Sunday_after_Pentecost|-|-|1
+2027-10-16|3|w|St. Hedwig|Saturday_after_XXI_Sunday_after_Pentecost|-|-|1
+2027-10-17|2|g|XXII Sunday after Pentecost|-|-|St. Margaret Mary Alacoque|1
+2027-10-18|2|r|St. Luke the Evangelist|Feria_II_after_XXII_Sunday_after_Pentecost|-|-|1
+2027-10-19|3|w|St. Peter of Alcantara|Feria_III_after_XXII_Sunday_after_Pentecost|-|-|1
+2027-10-20|3|w|St. John Cantius|Feria_IV_after_XXII_Sunday_after_Pentecost|-|-|1
+2027-10-21|4|g|Feria|Feria_V_after_XXII_Sunday_after_Pentecost|St. Hilarion;St. Ursula and Companions|-|1
+2027-10-22|4|g|Feria|Feria_VI_after_XXII_Sunday_after_Pentecost|-|-|1
+2027-10-23|3|w|St. Anthony Mary Claret|Saturday_after_XXII_Sunday_after_Pentecost|-|-|1
+2027-10-24|2|g|XXIII Sunday after Pentecost|-|-|St. Raphael the Archangel|1
+2027-10-25|4|g|Feria|Feria_II_after_XXIII_Sunday_after_Pentecost|Sts. Chrysanthus & Daria|-|1
+2027-10-26|4|g|Feria|Feria_III_after_XXIII_Sunday_after_Pentecost|St. Evaristus|-|1
+2027-10-27|4|g|Feria|Feria_IV_after_XXIII_Sunday_after_Pentecost|-|-|1
+2027-10-28|2|r|Sts. Simon & Jude|Feria_V_after_XXIII_Sunday_after_Pentecost|-|-|1
+2027-10-29|4|g|Feria|Feria_VI_after_XXIII_Sunday_after_Pentecost|-|-|1
+2027-10-30|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XXIII_Sunday_after_Pentecost|-|-|1
+2027-10-31|1|w|Christ the King|IV_Sunday_after_Epiphany|-|-|1
+2027-11-01|1|w|All Saints|Feria_II_after_IV_Sunday_after_Epiphany|-|-|1
+2027-11-02|1|b|Commemoration of All Souls|Feria_III_after_IV_Sunday_after_Epiphany|-|-|3
+2027-11-03|4|g|Feria|Feria_IV_after_IV_Sunday_after_Epiphany|-|-|1
+2027-11-04|3|w|St. Charles Borromeo|Feria_V_after_IV_Sunday_after_Epiphany|Sts. Vitalis and Agricola, Martyrs|-|1
+2027-11-05|4|g|Feria|Feria_VI_after_IV_Sunday_after_Epiphany|-|-|1
+2027-11-06|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_IV_Sunday_after_Epiphany|-|-|1
+2027-11-07|2|g|V Sunday after Epiphany|-|-|-|1
+2027-11-08|4|g|Feria|Feria_II_after_V_Sunday_after_Epiphany|Four Holy Crowned Martyrs|-|1
+2027-11-09|2|w|Dedication of the Archbasilica of Our Holy Savior|Feria_III_after_V_Sunday_after_Epiphany|St. Theodore|-|1
+2027-11-10|3|w|St. Andrew Avellino|Feria_IV_after_V_Sunday_after_Epiphany|Sts. Tryphonis, Respicii, et Nymphae|-|1
+2027-11-11|3|w|St. Martin of Tours|Feria_V_after_V_Sunday_after_Epiphany|St. Menna|-|1
+2027-11-12|3|r|St. Martin I|Feria_VI_after_V_Sunday_after_Epiphany|-|-|1
+2027-11-13|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_V_Sunday_after_Epiphany|St. Didacus|-|1
+2027-11-14|2|g|VI Sunday after Epiphany|-|-|St. Josaphat|1
+2027-11-15|3|w|St. Albert the Great|Feria_II_after_VI_Sunday_after_Epiphany|-|-|1
+2027-11-16|3|w|St. Gertrude the Great|Feria_III_after_VI_Sunday_after_Epiphany|-|-|1
+2027-11-17|3|w|St. Gregory the Wonderworker|Feria_IV_after_VI_Sunday_after_Epiphany|-|-|1
+2027-11-18|3|w|Dedication of the Basilicas of Sts. Peter & Paul|Feria_V_after_VI_Sunday_after_Epiphany|-|-|1
+2027-11-19|3|w|St. Elizabeth of Hungary|Feria_VI_after_VI_Sunday_after_Epiphany|St. Pontian|-|1
+2027-11-20|3|w|St. Felix of Valois|Saturday_after_VI_Sunday_after_Epiphany|-|-|1
+2027-11-21|2|g|XXIV Sunday after Pentecost|-|-|Presentation of the Blessed Virgin Mary|1
+2027-11-22|3|r|St. Cecilia|Feria_II_after_XXIV_Sunday_after_Pentecost|-|-|1
+2027-11-23|3|r|St. Clement I|Feria_III_after_XXIV_Sunday_after_Pentecost|St. Felicity|-|1
+2027-11-24|3|w|St. John of the Cross|Feria_IV_after_XXIV_Sunday_after_Pentecost|St. Chrysogonus|-|1
+2027-11-25|3|r|St. Catherine of Alexandria|Feria_V_after_XXIV_Sunday_after_Pentecost|-|-|1
+2027-11-26|3|w|St. Sylvester|Feria_VI_after_XXIV_Sunday_after_Pentecost|St. Peter of Alexandria|-|1
+2027-11-27|4|w|V Mass of the B. V. M. – Salve, Sancta Parens|Saturday_after_XXIV_Sunday_after_Pentecost|-|-|1
+2027-11-28|1|v|I Sunday of Advent|-|-|-|1
+2027-11-29|3|v|Feria II after I Sunday of Advent|-|St. Saturninus|-|1
+2027-11-30|2|r|St. Andrew|Feria_III_after_I_Sunday_of_Advent|-|-|1
+2027-12-01|3|v|Feria IV after I Sunday of Advent|-|-|-|1
+2027-12-02|3|r|St. Vivian|Feria_V_after_I_Sunday_of_Advent|Feria V after I Sunday of Advent|-|1
+2027-12-03|3|w|St. Francis Xavier|Feria_VI_after_I_Sunday_of_Advent|Feria VI after I Sunday of Advent|-|1
+2027-12-04|3|w|St. Peter Chrysologus|Sabbato_after_I_Sunday_of_Advent|Sabbato after I Sunday of Advent|-|1
+2027-12-05|1|v|II Sunday of Advent|-|-|St. Sabbas|1
+2027-12-06|3|w|St. Nicholas|Feria_II_after_II_Sunday_of_Advent|Feria II after II Sunday of Advent|-|1
+2027-12-07|3|w|St. Ambrose|Feria_III_after_II_Sunday_of_Advent|Feria III after II Sunday of Advent|-|1
+2027-12-08|1|w|Immaculate Conception of the Blessed Virgin Mary|Feria_IV_after_II_Sunday_of_Advent|-|-|1
+2027-12-09|3|v|Feria V after II Sunday of Advent|-|-|-|1
+2027-12-10|3|v|Feria VI after II Sunday of Advent|-|St. Melchiades|-|1
+2027-12-11|3|w|St. Damasus I|Sabbato_after_II_Sunday_of_Advent|Sabbato after II Sunday of Advent|-|1
+2027-12-12|1|pv|III Sunday of Advent|-|-|-|1
+2027-12-13|3|r|St. Lucy|Feria_II_after_III_Sunday_of_Advent|Feria II after III Sunday of Advent|-|1
+2027-12-14|3|pv|Feria III after III Sunday of Advent|-|-|-|1
+2027-12-15|2|v|Ember Wednesday of Advent|-|-|-|1
+2027-12-16|3|r|St. Eusebius|Feria_V_after_III_Sunday_of_Advent|Feria V after III Sunday of Advent|-|1
+2027-12-17|2|v|Ember Friday of Advent|-|-|-|1
+2027-12-18|2|v|Ember Saturday of Advent|-|-|-|1
+2027-12-19|1|v|IV Sunday of Advent|-|-|-|1
+2027-12-20|2|v|Feria II after IV Sunday of Advent|-|-|-|1
+2027-12-21|2|r|St. Thomas|Feria_III_after_IV_Sunday_of_Advent|Feria III after IV Sunday of Advent|-|1
+2027-12-22|2|v|Feria IV after IV Sunday of Advent|-|-|-|1
+2027-12-23|2|v|Feria V after IV Sunday of Advent|-|-|-|1
+2027-12-24|1|v|Vigil of Christmas|-|-|-|1
+2027-12-25|1|w|The Nativity of Our Lord|-|-|-|3
+2027-12-26|2|w|Sunday in the Octave of Christmas|-|St. Stephen|For Octave of the Nativity|1
+2027-12-27|2|w|St. John the Evangelist|-|For Octave of the Nativity|-|1
+2027-12-28|2|r|Holy Innocents|-|For Octave of the Nativity|-|1
+2027-12-29|2|w|Feria in the Octave of Christmas|-|St. Thomas Becket|-|1
+2027-12-30|2|w|Feria in the Octave of Christmas|-|-|-|1
+2027-12-31|2|w|Feria in the Octave of Christmas|-|St. Silvester|-|1
diff --git a/test/test_colitur.ml b/test/test_colitur.ml
index 4e32e04..b1c8a34 100644
--- a/test/test_colitur.ml
+++ b/test/test_colitur.ml
@@ -4,4 +4,4 @@ let () =
[ Test_date.suite; Test_computus.suite; Test_colour.suite; Test_slug.suite; Test_names.suite;
Test_overlay.suite; Test_temporal_ef.suite; Test_validate.suite; Test_precedence.suite;
Test_calendar.suite; Test_precedence_ef.suite; Test_sanctoral_ef.suite; Test_rite_ef.suite;
- Test_differential.suite ]
+ Test_differential.suite; Test_oracle.suite ]
diff --git a/test/test_oracle.ml b/test/test_oracle.ml
new file mode 100644
index 0000000..2cc9972
--- /dev/null
+++ b/test/test_oracle.ml
@@ -0,0 +1,607 @@
+(* Task 16: oracle harness vs missalemeum (sibling project's snapshot of
+ missalemeum.com/Divinum Officium data), EF only, 2026-2027 -- validation
+ layer 4 of the design spec's five (colitur CLAUDE.md "Validation" section;
+ layer 3, the lectio differential, is test_differential.ml, already green).
+
+ *** WHY THIS LAYER EXISTS, AND WHAT IT CAN DO THAT THE LECTIO DIFFERENTIAL
+ CANNOT (test_differential.ml's own header comment, limit 1) ***
+
+ The lectio differential compares colitur against data colitur was itself
+ BOOTSTRAPPED from (data/ef/sanctoral.sexp comes from lectio's tridentine-
+ calendar.ini) -- it cannot catch an error inherited from that bootstrap,
+ and it explicitly does not compare commemorations at all (lectio's
+ trailing tokens are losing candidates, not an RG 111 admitted set, per
+ that file's own limit 1). missalemeum is INDEPENDENT of colitur's
+ bootstrap chain, and its JSON carries a real admitted-commemorations
+ array (its own RG 111-shaped selection, not lectio's rejects) -- so this
+ file compares THREE axes the lectio differential cannot touch at all:
+ rank, colour (as SET membership, see below), and commemoration presence/
+ count. Slug IDENTITY is deliberately NOT compared (the brief: needs a
+ title->slug mapping, which is the data audit's business -- see the task
+ report -- not this automated comparator's).
+
+ *** THE FIXTURE'S OWN SHAPE (fixtures/missalemeum-ef-2026-2027.txt,
+ fixtures/missalemeum-ef-2026-2027.provenance, tools/
+ extract_missalemeum_oracle.py) ***
+
+ info.id (e.g. "sancti:01-02:1:w") encodes the PROPERS REUSED that day,
+ not the day's own rank or colour -- 137 of 730 days (19%) disagree
+ between the id-embedded rank and info.rank itself (task brief's own
+ premise was wrong here; the brief's extraction note has been corrected).
+ This file, like the extraction script, reads ONLY info.rank and
+ info.colors, never parses anything out of info.id.
+
+ info.colors is an ARRAY -- 14 of 730 days carry two colours (rose+violet
+ on Gaudete/Laetare per RG 131's indult, red+violet on Palm Sunday, black+
+ violet on Good Friday, violet+white on Holy Saturday -- one colour per
+ liturgical ACTION within that one civil day, which colitur's one-colour-
+ per-day model cannot represent, register §3b's own RG 126 note). So the
+ colour axis below is MEMBERSHIP (colitur's single colour must be one of
+ the oracle's set), never equality.
+
+ Four days carry more than one Mass in the JSON array (Christmas, All
+ Souls) -- the extraction script takes entry[0] throughout, VERIFIED
+ (not assumed) identical to every other Mass of the same day on every
+ field this file reads (see that script's own header and the task
+ report).
+
+ *** THE ALLOW-LIST (data/ef/expected-divergences-missalemeum.sexp) ***
+
+ A SEPARATE file from data/ef/expected-divergences.sexp (the lectio
+ allow-list): the two oracles disagree with colitur in different places
+ and for different reasons, and this file's own convention differs in one
+ deliberate way -- [verdict] is not always "colitur". Some entries are
+ genuine DATA GAPS this task found and could not fix here (data/ef/
+ sanctoral.sexp is bootstrapped from lectio, which is itself missing the
+ entries; RG 110's inseparable-Peter/Paul commemoration is unimplemented
+ code, a real feature this task did not build) -- honestly verdicted
+ [missalemeum] (colitur is short a feature or a row, not right), never
+ silently absorbed as if colitur were correct. One entry (M13) is
+ [verdict open]: adjudicated as unresolved, not resolved either way --
+ the brief's own explicit permission ("say so as an open item") used for
+ real, not defaulted past. See the task report for every entry's full
+ reasoning and primary-source citation. *)
+
+module Cal = Colitur_kernel.Calendar
+module Layer = Colitur_kernel.Layer
+module Overlay = Colitur_kernel.Overlay
+module LD = Colitur_kernel.Liturgical_day
+module Slug = Colitur_kernel.Slug
+module Date = Colitur_kernel.Date
+module Cel = Colitur_kernel.Celebration
+module Colour = Colitur_kernel.Colour
+module V = Rite_ef.Vocab_ef
+
+(* Same relative paths test_differential.ml uses: dune test runs from
+ _build/default/test/. *)
+let sanctoral_path = "../data/ef/sanctoral.sexp"
+let adjustments_path = "../data/ef/adjustments.sexp"
+let fixture_path = "fixtures/missalemeum-ef-2026-2027.txt"
+let allow_list_path = "../data/ef/expected-divergences-missalemeum.sexp"
+
+(* fixtures/missalemeum-ef-2026-2027.provenance carries the same digest and
+ the exact regeneration command. Asserted (not merely documented) for the
+ same reason test_differential.ml's own [fixture_sha256] is: a hand-edit
+ or partial re-extraction would otherwise silently turn the oracle into
+ an unlabelled snapshot of whatever someone last ran. *)
+let fixture_sha256 = "718eff1a03fa09c3927ef18d19fe7921c2d4d7611890c22566058b81fd7cc5ea"
+
+(* Identical technique to test_differential.ml's own [sha256_of_file]
+ (that file's own comment explains why: shelling out to [sha256sum]
+ rather than adding a crypto library dependency Task 15/16's frozen deps
+ do not include). Duplicated, not shared, for the same reason
+ [real_layer] below is -- neither file exposes an .mli the other could
+ depend on, and this is three lines. *)
+let sha256_of_file path =
+ let tmp = Filename.temp_file "colitur_oracle_sha256" ".txt" in
+ Fun.protect
+ ~finally:(fun () -> try Sys.remove tmp with Sys_error _ -> ())
+ (fun () ->
+ let cmd = Printf.sprintf "sha256sum %s > %s" (Filename.quote path) (Filename.quote tmp) in
+ let rc = Sys.command cmd in
+ if rc <> 0 then Alcotest.failf "sha256sum exited %d for %s (is it on PATH?)" rc path;
+ let ic = open_in tmp in
+ let line =
+ try input_line ic
+ with End_of_file ->
+ close_in ic;
+ Alcotest.failf "sha256sum produced no output for %s" path
+ in
+ close_in ic;
+ match String.index_opt line ' ' with
+ | Some i -> String.sub line 0 i
+ | None -> Alcotest.failf "unexpected sha256sum output for %s: %S" path line)
+
+let real_layer () =
+ let layer =
+ match Layer.load V.rank_of_sexp sanctoral_path with
+ | Ok l -> l
+ | Error e -> Alcotest.failf "%s: failed to load: %s" sanctoral_path e
+ in
+ let overlay =
+ match Overlay.load V.rank_of_sexp adjustments_path with
+ | Ok o -> o
+ | Error e -> Alcotest.failf "%s: failed to load: %s" adjustments_path e
+ in
+ let layer, diagnostics = Overlay.apply layer overlay in
+ Alcotest.(check (list string)) "the committed overlay applies cleanly, no diagnostics" []
+ (List.map Overlay.diagnostic_to_string diagnostics);
+ layer
+
+(* ---------------------------------------------------------------------- *)
+(* The oracle side: one line per day, as tools/extract_missalemeum_oracle *)
+(* .py's own header documents. *)
+(* ---------------------------------------------------------------------- *)
+
+type oracle_row = {
+ o_date : string;
+ o_rank : int;
+ o_colours : char list;
+ o_title : string;
+ o_commemorations : string list;
+ o_displaced : string list;
+}
+
+let explode s = List.init (String.length s) (String.get s)
+
+let split_list_field f = if f = "-" then [] else String.split_on_char ';' f
+
+let oracle_row_of_line line =
+ match String.split_on_char '|' line with
+ | [ date; rank; colours; title; _tempora; commemorations; displaced; _n_masses ] ->
+ { o_date = date;
+ o_rank = int_of_string rank;
+ o_colours = explode colours;
+ o_title = title;
+ o_commemorations = split_list_field commemorations;
+ o_displaced = split_list_field displaced }
+ | _ -> Alcotest.failf "malformed fixture line (expected 8 '|'-separated fields): %S" line
+
+let read_lines path =
+ let ic = open_in path in
+ let rec loop acc =
+ match input_line ic with
+ | line -> loop (line :: acc)
+ | exception End_of_file ->
+ close_in ic;
+ List.rev acc
+ in
+ loop []
+
+let oracle_rows () = List.map oracle_row_of_line (read_lines fixture_path)
+
+(* ---------------------------------------------------------------------- *)
+(* The colitur side: the SAME pipeline bin/main.ml's `colitur day` and *)
+(* test_differential.ml's own [colitur_rows_2005_2050] use -- *)
+(* Colitur_kernel.Calendar over the real committed data. Restricted to *)
+(* 2026-2027 (indexing 2025 too, for the same reason test_differential.ml *)
+(* indexes [y-1]: Calendar.year resolves one Advent-anchored liturgical *)
+(* year, which straddles two civil years). *)
+(* ---------------------------------------------------------------------- *)
+
+type colitur_row = { c_date : string; c_rank : int; c_colour : char; c_commemorations : string list }
+
+let rank_to_int = function V.Class1 -> 1 | V.Class2 -> 2 | V.Class3 -> 3 | V.Class4 -> 4
+
+let colour_to_char = function
+ | Colour.White -> 'w'
+ | Colour.Red -> 'r'
+ | Colour.Green -> 'g'
+ | Colour.Violet -> 'v'
+ | Colour.Rose -> 'p'
+ | Colour.Black -> 'b'
+
+let colitur_rows_2026_2027 () =
+ let layer = real_layer () in
+ let by_rata : (int, (V.season, V.rank) LD.t) Hashtbl.t = Hashtbl.create 800 in
+ for y = 2025 to 2027 do
+ let days = Cal.year Rite_ef.context layer y in
+ Array.iter (fun (d : (V.season, V.rank) LD.t) -> Hashtbl.replace by_rata (Date.to_rata d.LD.date) d) days
+ done;
+ let mk y m d = match Date.make ~year:y ~month:m ~day:d with Ok t -> t | Error e -> failwith e in
+ let rows = ref [] in
+ let d = ref (mk 2026 1 1) in
+ let stop = mk 2027 12 31 in
+ while Date.compare !d stop <= 0 do
+ (match Hashtbl.find_opt by_rata (Date.to_rata !d) with
+ | Some day ->
+ let cel = day.LD.observed in
+ let commemoration_slugs =
+ List.map (fun (c, _) -> Slug.to_string c.Cel.slug) day.LD.commemorations
+ in
+ rows :=
+ { c_date = Date.to_iso8601 day.LD.date;
+ c_rank = rank_to_int cel.Cel.rank;
+ c_colour = colour_to_char cel.Cel.colour;
+ c_commemorations = commemoration_slugs
+ }
+ :: !rows
+ | None -> Alcotest.failf "internal error: no resolved day for %s" (Date.to_iso8601 !d));
+ d := Date.add_days !d 1
+ done;
+ List.rev !rows
+
+(* ---------------------------------------------------------------------- *)
+(* Field-diff computation: the four axes the oracle actually supports *)
+(* (identity-by-slug is deliberately out of scope, see this file's own *)
+(* header). *)
+(* ---------------------------------------------------------------------- *)
+
+type field = Rank | Colour_f | Comm_presence | Comm_count
+
+let field_name = function
+ | Rank -> "rank"
+ | Colour_f -> "colour"
+ | Comm_presence -> "commemoration-presence"
+ | Comm_count -> "commemoration-count"
+
+let diff_fields (c : colitur_row) (o : oracle_row) =
+ let c_has = c.c_commemorations <> [] and o_has = o.o_commemorations <> [] in
+ List.filter_map
+ (fun x -> x)
+ [ (if c.c_rank = o.o_rank then None else Some Rank);
+ (if List.mem c.c_colour o.o_colours then None else Some Colour_f);
+ (if c_has = o_has then None else Some Comm_presence);
+ (* Count is only meaningful once presence already agrees (both non-empty):
+ a presence mismatch already flags the row via [Comm_presence] above,
+ and comparing lengths across a 0-vs-N split would just restate that
+ same disagreement under a second name. *)
+ (if c_has && o_has && List.length c.c_commemorations <> List.length o.o_commemorations then
+ Some Comm_count
+ else None)
+ ]
+
+(* ---------------------------------------------------------------------- *)
+(* The cited allow-list (data/ef/expected-divergences-missalemeum.sexp). *)
+(* Each predicate is gated on an EXACT, literal date set (never a date *)
+(* range or a slug pattern -- with at most 4 dates per id, a literal list *)
+(* costs nothing and cannot silently widen to absorb an unrelated future *)
+(* mismatch the way a range could), AND an exact/subset diff shape, the *)
+(* same double-gate test_differential.ml's own [layer_c_reason] uses. *)
+(* ---------------------------------------------------------------------- *)
+
+let subset xs ys = List.for_all (fun x -> List.mem x ys) xs
+
+let contains_substring s ~needle =
+ let ls = String.length s and ln = String.length needle in
+ let rec at i = i + ln <= ls && (String.sub s i ln = needle || at (i + 1)) in
+ ln = 0 || at 0
+
+(* M1 -- RG 33 (corrected, precedence_ef.ml's own [is_omissible_vigil]):
+ missalemeum does not implement RG 33's mandatory omission of a II/III-
+ class vigil impeded by a Sunday -- 28 June 2026 (Vigil of Sts Peter &
+ Paul, II class) still shows a commemoration of the vigil on the V Sunday
+ after Pentecost; 9 August 2026 (Vigil of St Lawrence, III class) shows
+ the vigil as the day's FULL OBSERVED OFFICE, not merely a commemoration,
+ displacing the XI Sunday after Pentecost entirely. Both wrong per RG 33's
+ own "in dominica quavis" (ANY Sunday, unqualified) -- verdict colitur. *)
+let m1_dates = [ "2026-06-28"; "2026-08-09" ]
+
+(* M2 -- RG 91 entry 27 ("Officium sanctae Mariae in sabbato"): every
+ otherwise-unoccupied IV-class Saturday should carry the votive Office of
+ the BVM (white; missalemeum's own title cycles "I".."V Mass of the
+ B. V. M. - Salve, Sancta Parens"), a genuinely DISTINCT office from an
+ ordinary green/violet feria. temporal_ef.ml's [band] already carries an
+ entry-27 comment acknowledging this row of RG 91 exists, but nothing in
+ [Temporal_ef.temporal]'s actual CONSTRUCTION builds this office -- an
+ unimpeded Time-after-Epiphany/-Pentecost Saturday still gets the bare
+ ferial slug and [season_colour]'s green. A genuine, primary-attested
+ FEATURE GAP (not a citation dispute) -- verdict missalemeum: colitur is
+ short a whole office here, not merely differently-opinioned. Registered
+ as an open item (register §6) rather than built in this task: it needs
+ its own proper texts/citations, the same scope line "Major Litanies"
+ (M5 below) already sits on. Matched on the oracle's own title substring,
+ not a hardcoded date list -- the title IS the distinguishing evidence,
+ and every Paschaltide occurrence (where colitur's season colour is
+ already white, RG 119) never reaches this predicate at all, since its
+ diffs are already empty before [layer_m_reason] is ever called. *)
+let bvm_saturday_title = "Salve, Sancta Parens"
+
+(* M3 -- RG 87 (Minor Litanies/Rogations): the SAME gap the lectio
+ differential's own C8 already names (data/ef/expected-divergences.sexp)
+ -- missalemeum, like lectio, computes no Rogation day at all and shows
+ the plain paschaltide-week feria instead. Only ONE date in this window
+ shows it (3 May 2027, Rogation Monday) because every other Rogation day
+ here is won by a saint anyway (both sides then agree on the SAINT's own
+ identity, with only the underlying temporal identity differing, which
+ this comparator's rank/colour/commemoration axes do not expose). Verdict
+ colitur, same citation as lectio's own C8. *)
+let m3_dates = [ "2027-05-03" ]
+
+(* M4 -- a genuine DATA GAP, primary-source-confirmed: the 1962 calendarium
+ itself lists, under 28 January, "S. Petri Nolasci Conf., III classis. /
+ Com. S. Agnetis Virg. et Mart., secundo" -- a second commemoration of
+ St Agnes (distinct from her main 21 January feast) that data/ef/
+ sanctoral.sexp does not carry at all. Traced upstream: lectio's own
+ tridentine-calendar.ini has no 01-28 entry beyond [peter-nolasco]
+ either, so colitur inherited the gap from its bootstrap source, not
+ from the bootstrap tool mis-reading a present entry. Cannot be fixed in
+ this task (data/ef/sanctoral.sexp is bootstrapped from lectio, per
+ CLAUDE.md's binding decision 3; lectio itself needs the entry first,
+ and this task does not touch ~/git/projects/lectio) -- verdict
+ missalemeum, tracked as a register §6 open item. *)
+let m4_dates = [ "2026-01-28"; "2027-01-28" ]
+
+(* M5 -- register §6's OWN already-open item, independently confirmed by
+ the oracle: "Major Litanies (25 April, RG 80) are not yet computed" --
+ missalemeum's commemoration "Pro rogationibus" ("for the Rogations") on
+ St Mark's day (25 April, the Major Litanies' fixed date) is exactly the
+ missing office. Not a new finding; recorded here so the automated
+ comparator does not report it as an unexplained mismatch, and cross-
+ referenced from the register so a reader sees both. Verdict missalemeum
+ (colitur is missing a real, cited office; register §6 already tracks
+ it). Only ONE date below, not two: 25 April 2026 is a Saturday (Mark
+ wins outright, colitur's commemoration list is empty where the oracle's
+ is not -- a visible presence gap); 25 April 2027 is a Sunday, where the
+ Sunday wins on BOTH sides and each side's own single slot goes to a
+ DIFFERENT candidate (colitur: Mark himself, admitted under RG 111(b)'s
+ "de festo II classis"; missalemeum: the Major Litanies) -- both
+ non-empty, same count, so this comparator's deliberately-not-slug-
+ identity axes cannot see that year's instance at all (see the task
+ report). *)
+let m5_dates = [ "2026-04-25" ]
+
+(* M6 -- the reverse of M4/M7/M9: the primary calendarium's own row for 14
+ August reads, in full, "Vigilia, II classis." -- nothing else. No
+ commemoration is listed for that date anywhere in the source this
+ project treats as authoritative (CLAUDE.md binding decision 1). data/ef/
+ sanctoral.sexp agrees (a single entry, [vigil-of-the-assumption], 14
+ Aug). missalemeum's own "St. Eusebius" commemoration for that date has
+ no support in the 1962 universal calendar found here (a DIFFERENT St
+ Eusebius, bishop and martyr, is genuinely commemorated 16 December,
+ matching lectio's own [eusebius] entry at that date -- not this one).
+ Verdict colitur: this is the one direction among M4/M6/M7/M9 where the
+ oracle itself appears to be carrying data outside the 1962 universal
+ calendar (a pre-1955 survival or a different edition), not colitur
+ missing something real. *)
+let m6_dates = [ "2026-08-14"; "2027-08-14" ]
+
+(* M7 -- a genuine DATA GAP, primary-source-confirmed, the same shape as
+ M4: the calendarium's own 26 October row reads "Com. S. Evaristi Papæ
+ et Mart." (Commemoration of St Evaristus, Pope and Martyr) -- absent
+ from data/ef/sanctoral.sexp, and absent from lectio's own tridentine-
+ calendar.ini for 10-26 (no entry at all for that date), so this is
+ another bootstrap-source gap, not fixable without touching lectio.
+ Verdict missalemeum, register §6 open item. *)
+let m7_dates = [ "2026-10-26"; "2027-10-26" ]
+
+(* M8 -- RG 109(a) ("of a Sunday" is always privileged) + RG 111(a) ("on
+ I-class days... none save one privileged"): when a FIXED I-class feast
+ (All Saints, 1 Nov; the Assumption, 15 Aug) lands on an ordinary Sunday,
+ the impeded Sunday IS the one privileged commemoration RG 111(a) admits
+ -- already an established, independently-tested rule in this codebase
+ (test_precedence_ef.ml's "RG95/RG109(a): an impeded I-class SUNDAY does
+ NOT transfer -- it is Commemorated and Privileged"). missalemeum shows
+ no commemoration at all on either occurrence in this window. Verdict
+ colitur. *)
+let m8_dates = [ "2026-11-01"; "2027-08-15" ]
+
+(* M9 -- a genuine DATA GAP, the same shape as M4/M7: the calendarium's own
+ 9 November row reads, alongside the Dedication of the Archbasilica (II
+ class), "Com. S. Theodori Mart." (Commemoration of St Theodore,
+ Martyr) -- absent from data/ef/sanctoral.sexp and from lectio's own
+ 11-09 entry (dedication-of-the-archbasilica-of-our-holy-savior alone,
+ no second entry for that date). Verdict missalemeum, register §6 open
+ item. *)
+let m9_dates = [ "2026-11-09"; "2027-11-09" ]
+
+(* M14 -- a genuine DATA GAP, the same shape as M4/M7/M9: the calendarium's
+ own 14 May row reads "Com. S. Bonifatii Mart." (a commemoration-only St
+ Boniface, Martyr -- DIFFERENT from the II-class St Boniface, Bishop and
+ Martyr, of 5 June, which data/ef/sanctoral.sexp and lectio both already
+ carry correctly) -- absent from data/ef/sanctoral.sexp and from lectio's
+ own tridentine-calendar.ini for 05-14 (no entry at all for that date).
+ Verdict missalemeum, register §6 open item. *)
+let m14_dates = [ "2027-05-14" ]
+
+(* M10 -- RG 109(e), unqualified text ("de feriis Adventus, Quadragesimae
+ et Passionis" -- OF THE FERIAS OF ADVENT, not "of the Advent ferias 17-
+ 23 December only"; that narrower window is RG 91 entry 18's own
+ OCCURRENCE-table dignity, a different axis from RG 109's commemoration-
+ privilege list, register §4's own citations keep the two separate).
+ colitur commemorates the losing early-Advent feria (the Monday after
+ Advent I, 30 Nov; the Tuesday/Wednesday after Advent II, 8 Dec) when a
+ saint wins those days -- missalemeum shows nothing on these specific
+ four rows, even though it DOES show equivalent later-Advent-feria
+ commemorations elsewhere in this same window (2-21 December, matching
+ colitur exactly on every one of those -- see the task report), which is
+ why this reads as a missalemeum-side inconsistency on these four
+ particular rows rather than a textually-narrower rule this task missed.
+ Verdict colitur. *)
+let m10_dates = [ "2026-11-30"; "2027-11-30"; "2026-12-08"; "2027-12-08" ]
+
+(* M11 -- missalemeum's own "For Octave of the Nativity" commemoration/
+ displaced entry on 26, 27(2027)/28 December carries info.rank 4 in the
+ raw JSON (checked directly, not inferred) -- a generic, always-present,
+ lowest-dignity placeholder its OWN data model seems to attach to every
+ day within the Nativity Octave, distinct from RG 91 entry 17's real
+ "days within the Octave" office (which colitur already models correctly
+ -- but only for 29-31 December, since 26-28 are the NAMED feasts
+ Stephen/John/the Innocents themselves, sanctoral not temporal,
+ temporal_ef.ml's own comment on [named]). No RG paragraph found here
+ supports a SEPARATE rank-4 commemoration alongside Stephen/John/the
+ Innocents' own (much higher) offices. Verdict colitur: read as
+ missalemeum's own bookkeeping artifact, not a liturgical fact -- flagged
+ as an open item rather than confidently dismissed, since the primary-
+ source search for this specific point was not exhaustive (see the task
+ report). *)
+let m11_dates = [ "2026-12-26"; "2026-12-28"; "2027-12-27"; "2027-12-28" ]
+
+(* M12 -- RG 110, primary text: "In Officio et Missa S. Petri semper fit
+ commemoratio S. Pauli, et vicissim" -- in the Office and Mass of EITHER
+ Peter or Paul, a commemoration of the OTHER is ALWAYS made (the
+ "inseparable commemoration"), uncapped by RG 111's ordinary admission
+ count ("in numero orationum computando, pro unica habeantur" -- counted
+ as one for counting purposes, i.e. it rides alongside whatever RG 111
+ already admits). Unimplemented in this codebase -- confirmed by the one
+ row in this window where it is visible: 22 February 2027 (Chair of
+ St Peter) shows only the privileged Lent feria commemorated in colitur,
+ while missalemeum shows that AND "St. Paul". A genuine, primary-cited
+ feature gap -- verdict missalemeum, register §6 open item. Real but
+ NARROW: every other Peter/Paul office in this window (29 June, both
+ years; 1 August M4-adjacent dates were checked and found clean) either
+ had no room for the extra commemoration to become visible against this
+ comparator's axes, or fell on a day this predicate does not otherwise
+ touch -- see the task report for the specific check. *)
+let m12_dates = [ "2027-02-22" ]
+
+(* M13 -- OPEN, NOT adjudicated (the brief's own explicit permission,
+ "say so as an open item rather than absorbing it"). 19 March 2027: St
+ Joseph (I class, 19 March) falls on the Friday of Passion Week. The
+ 1962 calendarium's own March table carries a standing note, "Feria VI
+ post dominicam I Passionis: Commemoratio septem Dolorum B. Mariae
+ Virg." (a fixed commemoration of Our Lady's Seven Sorrows for that
+ Friday, EVERY year, confirmed real) -- and missalemeum shows Joseph
+ entirely DISPLACED that year, with the Friday's own office (III class,
+ violet) observed and the Seven Sorrows commemorated instead. RG 91's
+ plain table (entry 11-13, I-class feast, vs entry 22, an ordinary III-
+ class Passiontide feria) gives Joseph the day outright, with no general
+ RG 96 collision requiring a transfer -- so either (a) colitur's plain
+ reading is right and missalemeum is wrong, (b) a MORE SPECIFIC rubric
+ (most plausibly attached to St Joseph's own Proprium Sanctorum entry,
+ the same shape as the Annunciation's own Attamen clause, register §4)
+ overrides the general table for this exact collision and this task did
+ not find its text, or (c) the Seven Sorrows commemoration itself
+ somehow outranks an ordinary I-class feast on this one Friday, which
+ nothing found here supports either. Extensive but non-exhaustive
+ primary-source search (see the task report) did not settle it.
+ Separately, but confirmed regardless of the adjudication above: colitur
+ does not implement the Seven-Sorrows-of-Passion-Friday commemoration at
+ all, in any year -- a real, primary-attested gap, register §6 open
+ item. *)
+let m13_dates = [ "2027-03-19" ]
+
+let layer_m_reason (c : colitur_row) (o : oracle_row) diffs =
+ if diffs = [] then None
+ else if List.mem c.c_date m1_dates && subset diffs [ Rank; Colour_f; Comm_presence ] then Some "M1"
+ else if contains_substring o.o_title ~needle:bvm_saturday_title && diffs = [ Colour_f ] then Some "M2"
+ else if List.mem c.c_date m3_dates && diffs = [ Colour_f ] then Some "M3"
+ else if List.mem c.c_date m4_dates && diffs = [ Comm_presence ] then Some "M4"
+ else if List.mem c.c_date m5_dates && diffs = [ Comm_presence ] then Some "M5"
+ else if List.mem c.c_date m6_dates && diffs = [ Comm_presence ] then Some "M6"
+ else if List.mem c.c_date m7_dates && diffs = [ Comm_presence ] then Some "M7"
+ else if List.mem c.c_date m8_dates && diffs = [ Comm_presence ] then Some "M8"
+ else if List.mem c.c_date m9_dates && diffs = [ Comm_presence ] then Some "M9"
+ else if List.mem c.c_date m14_dates && diffs = [ Comm_presence ] then Some "M14"
+ else if List.mem c.c_date m10_dates && diffs = [ Comm_presence ] then Some "M10"
+ else if List.mem c.c_date m11_dates && diffs = [ Comm_presence ] then Some "M11"
+ else if List.mem c.c_date m12_dates && diffs = [ Comm_count ] then Some "M12"
+ else if List.mem c.c_date m13_dates && subset diffs [ Rank; Colour_f ] then Some "M13"
+ else None
+
+(* ---------------------------------------------------------------------- *)
+(* data/ef/expected-divergences-missalemeum.sexp loading -- same shape as *)
+(* test_differential.ml's own [allow_entry]/[load_allow_list]. *)
+(* ---------------------------------------------------------------------- *)
+
+open Sexplib0.Sexp_conv
+
+type allow_entry = { id : string; citation : string; verdict : string; note : string; expected_rows : int }
+[@@deriving sexp]
+
+let load_allow_list () =
+ let sexps =
+ try Sexplib.Sexp.load_sexps allow_list_path
+ with e -> Alcotest.failf "%s: failed to load: %s" allow_list_path (Printexc.to_string e)
+ in
+ List.map allow_entry_of_sexp sexps
+
+(* ---------------------------------------------------------------------- *)
+(* The comparison itself. *)
+(* ---------------------------------------------------------------------- *)
+
+type outcome = Matched | Explained of string | Unexplained of field list
+
+let compare_streams () =
+ let oracle = oracle_rows () in
+ let colitur = colitur_rows_2026_2027 () in
+ (oracle, colitur)
+
+let classify oracle colitur =
+ List.map2
+ (fun (o : oracle_row) (c : colitur_row) ->
+ if not (String.equal o.o_date c.c_date) then
+ Alcotest.failf "streams misaligned: oracle %s vs colitur %s" o.o_date c.c_date;
+ let diffs = diff_fields c o in
+ if diffs = [] then (c, o, Matched)
+ else
+ match layer_m_reason c o diffs with
+ | Some id -> (c, o, Explained id)
+ | None -> (c, o, Unexplained diffs))
+ oracle colitur
+
+let describe_unexplained (c : colitur_row) (o : oracle_row) diffs =
+ Printf.sprintf "%s: %s differ -- colitur=(rank=%d colour=%c comms=[%s]) oracle=(rank=%d colours=[%s] \
+ title=%S comms=[%s] displaced=[%s])"
+ c.c_date
+ (String.concat "," (List.map field_name diffs))
+ c.c_rank c.c_colour
+ (String.concat ";" c.c_commemorations)
+ o.o_rank
+ (String.concat "" (List.map (String.make 1) o.o_colours))
+ o.o_title
+ (String.concat ";" o.o_commemorations)
+ (String.concat ";" o.o_displaced)
+
+let test_fixture_checksum () =
+ Alcotest.(check string) "fixture SHA-256 matches its provenance note" fixture_sha256
+ (sha256_of_file fixture_path)
+
+let test_dates_align () =
+ let oracle, colitur = compare_streams () in
+ Alcotest.(check int) "both streams have 730 rows (2026 + 2027, both non-leap)" 730 (List.length oracle);
+ Alcotest.(check int) "colitur recomputed the same number of rows" (List.length oracle) (List.length colitur);
+ let mismatched =
+ List.filter_map
+ (fun (o, c) -> if String.equal o.o_date c.c_date then None else Some (o.o_date, c.c_date))
+ (List.combine oracle colitur)
+ in
+ Alcotest.(check (list (pair string string))) "no misaligned dates" [] mismatched
+
+(* The core assertion: every one of the 42 raw differences across all four
+ axes (rank, colour-membership, commemoration-presence, commemoration-
+ count) is named in the cited allow-list. Nothing else passes silently. *)
+let test_no_unexplained_differences () =
+ let oracle, colitur = compare_streams () in
+ let classified = classify oracle colitur in
+ let unexplained =
+ List.filter_map
+ (fun (c, o, outcome) ->
+ match outcome with Unexplained diffs -> Some (describe_unexplained c o diffs) | _ -> None)
+ classified
+ in
+ Alcotest.(check (list string)) "no differences outside the cited allow-list" [] unexplained
+
+(* Teeth, not just green: EVERY allow-list id's actual row count over this
+ fixture must equal what data/ef/expected-divergences-missalemeum.sexp
+ declares, in BOTH directions -- the same double-check test_differential
+ .ml's own "Layer C counts match citations" test makes for the lectio
+ allow-list. *)
+let test_layer_m_counts_match_citations () =
+ let oracle, colitur = compare_streams () in
+ let classified = classify oracle colitur in
+ let actual_counts = Hashtbl.create 16 in
+ List.iter
+ (fun (_, _, outcome) ->
+ match outcome with
+ | Explained id ->
+ Hashtbl.replace actual_counts id (1 + Option.value ~default:0 (Hashtbl.find_opt actual_counts id))
+ | _ -> ())
+ classified;
+ let declared = load_allow_list () in
+ let expected = List.sort compare (List.map (fun e -> (e.id, e.expected_rows)) declared) in
+ let actual = List.sort compare (Hashtbl.fold (fun id n acc -> (id, n) :: acc) actual_counts []) in
+ Alcotest.(check (list (pair string int)))
+ "every allow-list id's actual row count matches its citation's expected_rows, and no id is unused or \
+ undeclared"
+ expected actual
+
+let suite =
+ ( "oracle (missalemeum, EF, 2026-2027)",
+ [ Alcotest.test_case "fixture SHA-256 matches its provenance note" `Quick test_fixture_checksum;
+ Alcotest.test_case "streams are 730 rows each, dates aligned 1:1" `Quick test_dates_align;
+ Alcotest.test_case "every difference is named in the cited allow-list -- none unexplained" `Quick
+ test_no_unexplained_differences;
+ Alcotest.test_case "allow-list counts match data/ef/expected-divergences-missalemeum.sexp exactly"
+ `Quick test_layer_m_counts_match_citations
+ ] )