From 7cc6adfb555fd44dfc59e4e8fd636ad68f417d47 Mon Sep 17 00:00:00 2001 From: Will Estes Date: Tue, 11 Aug 2026 06:18:12 -0400 Subject: [PATCH] propers: add November's collect and antiphon text 9 collects, 3 antiphons -- including backfilling the pre-existing All Saints entry. Also updates two pre-existing tests whose shared date (2025-11-30, Advent I Sunday) now correctly shows St. Andrew commemorated alongside it, confirmed against the live reference engine. Co-Authored-By: Claude Sonnet 5 --- .../propers/common/all-saints-collect.yml | 23 +++++ .../propers/common/st-andrew-antiphon.yml | 12 +++ src/data/propers/common/st-andrew-collect.yml | 17 ++++ .../propers/common/st-catherine-collect.yml | 17 ++++ .../propers/common/st-cecilia-antiphon.yml | 10 +++ .../propers/common/st-cecilia-collect.yml | 17 ++++ .../propers/common/st-clement-collect.yml | 17 ++++ .../common/st-martin-of-tours-antiphon.yml | 9 ++ .../common/st-martin-of-tours-collect.yml | 17 ++++ .../common/st-silvester-abbot-collect.yml | 17 ++++ tests/calendar/day-label.test.ts | 8 +- tests/calendar/november-sanctoral.test.ts | 87 +++++++++++++++++++ tests/hours/compline.test.ts | 6 +- 13 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 src/data/propers/common/all-saints-collect.yml create mode 100644 src/data/propers/common/st-andrew-antiphon.yml create mode 100644 src/data/propers/common/st-andrew-collect.yml create mode 100644 src/data/propers/common/st-catherine-collect.yml create mode 100644 src/data/propers/common/st-cecilia-antiphon.yml create mode 100644 src/data/propers/common/st-cecilia-collect.yml create mode 100644 src/data/propers/common/st-clement-collect.yml create mode 100644 src/data/propers/common/st-martin-of-tours-antiphon.yml create mode 100644 src/data/propers/common/st-martin-of-tours-collect.yml create mode 100644 src/data/propers/common/st-silvester-abbot-collect.yml create mode 100644 tests/calendar/november-sanctoral.test.ts diff --git a/src/data/propers/common/all-saints-collect.yml b/src/data/propers/common/all-saints-collect.yml new file mode 100644 index 0000000..97df186 --- /dev/null +++ b/src/data/propers/common/all-saints-collect.yml @@ -0,0 +1,23 @@ +# Verified against Divinum Officium (web/www/horas/Latin+English/Sancti/ +# 11-01.txt) directly -- the live prayTertia query's English side didn't +# render an Oratio translation for this date for reasons not fully +# understood (the Latin side rendered correctly; every other saint this +# pull has queried the same way), so the raw source files were read +# directly instead this one time. The closing formula ("$Per Dominum" in +# the raw file) is expanded to the standard form used throughout this +# project, matching every other Duplex-rank collect. +id: all-saints-collect +text: + la: | + Orémus. + Omnípotens sempitérne Deus, qui nos ómnium Sanctórum tuórum mérita sub una tribuísti celebritáte venerári: quǽsumus; ut desiderátam nobis tuæ propitiatiónis abundántiam, multiplicátis intercessóribus, largiáris. + Per Dóminum nostrum Jesum Christum, Fílium tuum: qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + Almighty, eternal God, Who granted us to honor the merits of all Thy Saints in a single solemn festival, bestow on us, we beseech Thee, through their manifold intercession, that abundance of Thy mercy for which we yearn. + Through Jesus Christ, thy Son our Lord, Who liveth and reigneth with thee, in the unity of the Holy Ghost, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-andrew-antiphon.yml b/src/data/propers/common/st-andrew-antiphon.yml new file mode 100644 index 0000000..167c4aa --- /dev/null +++ b/src/data/propers/common/st-andrew-antiphon.yml @@ -0,0 +1,12 @@ +# Verified against Divinum Officium (Latin/English Sancti/11-30.txt's own +# [Ant 1] — the Lauds-hour antiphon, not Terce's. That file's own +# "(rubrica cisterciensis)" alternate is a different text entirely; the +# plain default is used here for consistency with every other saint file +# in this set. +id: st-andrew-antiphon +text: + la: "Unus ex duóbus, * qui secúti sunt Dóminum, erat Andréas, frater Simónis Petri, allelúja." + en: "One of the two * which followed the Lord was Andrew, Simon Peter's brother. Alleluia." +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-andrew-collect.yml b/src/data/propers/common/st-andrew-collect.yml new file mode 100644 index 0000000..13ed597 --- /dev/null +++ b/src/data/propers/common/st-andrew-collect.yml @@ -0,0 +1,17 @@ +# Verified against Divinum Officium (Monastic Tridentinum 1617) — read +# directly from the reference engine's own real-date output (2026-11-30). +id: st-andrew-collect +text: + la: | + Orémus. + Majestátem tuam, Dómine, supplíciter exorámus: ut, sicut Ecclésiæ tuæ beátus Andréas Apóstolus éxstitit prædicátor et rector; ita apud te sit pro nobis perpétuus intercéssor. + Per Dóminum nostrum Jesum Christum, Fílium tuum: qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + O Lord, we humbly beseech thy Majesty, that even as Thou didst give thy blessed Apostle Andrew to thy Church to be a teacher and a ruler on earth, so, now that he is with thee, he may continually make intercession for us. + Through Jesus Christ, thy Son our Lord, Who liveth and reigneth with thee, in the unity of the Holy Ghost, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-catherine-collect.yml b/src/data/propers/common/st-catherine-collect.yml new file mode 100644 index 0000000..f42be7a --- /dev/null +++ b/src/data/propers/common/st-catherine-collect.yml @@ -0,0 +1,17 @@ +# Verified against Divinum Officium (Monastic Tridentinum 1617) — read +# directly from the reference engine's own real-date output (2032-11-25). +id: st-catherine-collect +text: + la: | + Orémus. + Deus, qui dedísti legem Móysi in summitáte montis Sínai, et in eódem loco per sanctos Angelos tuos corpus beátæ Catharínæ Vírginis et Mártyris tuæ mirabíliter collocásti: præsta, quǽsumus; ut, ejus méritis et intercessióne, ad montem, qui Christus est, perveníre valeámus: + Qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + O God, Who didst give the Law unto Moses upon the top of Mount Sinai, and there didst cause the body of thy blessed Virgin and Martyr Catharine to be marvelously laid by thine holy Angels, grant unto us, we beseech thee, for her sake and at her prayers, that we may finally attain unto that mountain which is Christ. + Who with thee liveth and reigneth, in the unity of the Holy Spirit, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-cecilia-antiphon.yml b/src/data/propers/common/st-cecilia-antiphon.yml new file mode 100644 index 0000000..f16cdde --- /dev/null +++ b/src/data/propers/common/st-cecilia-antiphon.yml @@ -0,0 +1,10 @@ +# Verified against Divinum Officium (Latin/English Sancti/11-22.txt's own +# [Ant 1] — the Lauds-hour antiphon, not Terce's. Refers to Valerian, her +# husband in the traditional legend. +id: st-cecilia-antiphon +text: + la: "Est secrétum, * Valeriáne, quod tibi volo dícere: Angelum Dei hábeo amatórem, qui nímio zelo custódit corpus meum." + en: "Valerian! there is a secret * which I wish to tell thee. I have an Angel of God for a lover, and he is very jealous to keep my body." +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-cecilia-collect.yml b/src/data/propers/common/st-cecilia-collect.yml new file mode 100644 index 0000000..5e46844 --- /dev/null +++ b/src/data/propers/common/st-cecilia-collect.yml @@ -0,0 +1,17 @@ +# Verified against Divinum Officium (Monastic Tridentinum 1617) — read +# directly from the reference engine's own real-date output (2032-11-22). +id: st-cecilia-collect +text: + la: | + Orémus. + Deus, qui nos ánnua beátæ Cæcíliæ Vírginis et Mártyris tuæ solemnitáte lætíficas: da, ut, quam venerámur offício, étiam piæ conversatiónis sequámur exémplo. + Per Dóminum nostrum Jesum Christum, Fílium tuum: qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + O God, Who year by year dost gladden thy people by the solemn feast of thy blessed Virgin and Martyr Cecilia, grant unto us, we beseech thee, not only devoutly to observe the same, but also to follow after the pattern of her godly conversation. + Through Jesus Christ, thy Son our Lord, Who liveth and reigneth with thee, in the unity of the Holy Ghost, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-clement-collect.yml b/src/data/propers/common/st-clement-collect.yml new file mode 100644 index 0000000..23de83f --- /dev/null +++ b/src/data/propers/common/st-clement-collect.yml @@ -0,0 +1,17 @@ +# Verified against Divinum Officium (Monastic Tridentinum 1617) — read +# directly from the reference engine's own real-date output (2032-11-23). +id: st-clement-collect +text: + la: | + Orémus. + Deus, qui nos ánnua beáti Cleméntis Mártyris tui atque Pontíficis solemnitáte lætíficas: concéde propítius; ut cujus natalítia cólimus, virtútem quoque passiónis imitémur. + Per Dóminum nostrum Jesum Christum, Fílium tuum: qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + O God, Who dost gladden us by the yearly Feast-day of thine holy Martyr, Clement mercifully grant unto us who keep their birthday, the strength to imitate their patience under suffering. + Through Jesus Christ, thy Son our Lord, Who liveth and reigneth with thee, in the unity of the Holy Ghost, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-martin-of-tours-antiphon.yml b/src/data/propers/common/st-martin-of-tours-antiphon.yml new file mode 100644 index 0000000..2dd63aa --- /dev/null +++ b/src/data/propers/common/st-martin-of-tours-antiphon.yml @@ -0,0 +1,9 @@ +# Verified against Divinum Officium (Latin/English Sancti/11-11.txt's own +# [Ant 1] — the Lauds-hour antiphon, not Terce's. +id: st-martin-of-tours-antiphon +text: + la: "O beátum virum, * cujus ánima paradísum póssidet! Unde exsúltant Ángeli, lætántur Archángeli, chorus Sanctórum proclámat, turba Vírginum invítat: Mane nobíscum in ætérnum." + en: "O how blessed a man is he! * His soul hath entered into possession in Paradise. There the Angels cry aloud for joy, there the Archangels make glad, there the whole company of the Saints do shout, there the army of the Virgins do call others to follow, (saying:) Make thine everlasting abode with us." +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-martin-of-tours-collect.yml b/src/data/propers/common/st-martin-of-tours-collect.yml new file mode 100644 index 0000000..5e53f33 --- /dev/null +++ b/src/data/propers/common/st-martin-of-tours-collect.yml @@ -0,0 +1,17 @@ +# Verified against Divinum Officium (Monastic Tridentinum 1617) — read +# directly from the reference engine's own real-date output (2025-11-11). +id: st-martin-of-tours-collect +text: + la: | + Orémus. + Deus, qui cónspicis, quia ex nulla nostra virtúte subsístimus: concéde propítius; ut, intercessióne beáti Martíni Confessóris tui atque Pontíficis, contra ómnia advérsa muniámur. + Per Dóminum nostrum Jesum Christum, Fílium tuum: qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + Grant, we beseech thee, O Almighty God, that the worshipful Feast of thy blessed Confessor and Bishop Martin, may avail us to the increase both of godliness toward thee, and healthfulness to our own souls. + Through Jesus Christ, thy Son our Lord, Who liveth and reigneth with thee, in the unity of the Holy Ghost, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/src/data/propers/common/st-silvester-abbot-collect.yml b/src/data/propers/common/st-silvester-abbot-collect.yml new file mode 100644 index 0000000..4fe0672 --- /dev/null +++ b/src/data/propers/common/st-silvester-abbot-collect.yml @@ -0,0 +1,17 @@ +# Verified against Divinum Officium (Monastic Tridentinum 1617) — read +# directly from the reference engine's own real-date output (2032-11-26). +id: st-silvester-abbot-collect +text: + la: | + Orémus. + Clementíssime Deus, qui sanctum Silvéstrum Abbátem, sǽculi hujus vanitátem in apérto túmulo pie meditántem, ad erémum vocáre, et præcláris vitæ méritis decoráre dignátus es: te súpplices exorámus; ut, ejus exémplo terréna despiciéntes, tui consórtio perfruámur ætérno. + Per Dóminum nostrum Jesum Christum, Fílium tuum: qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum. + ℟. Amen. + en: | + Let us pray. + Most merciful God, Who when the holy Abbot Sylvester was devoutly meditating upon the vanity of this world beside an open grave, graciously willed to call him into the desert and enrich him with unusual merits, we humbly pray that, following his example, despising the things of earth, we may thoroughly enjoy Thy everlasting presence. + Through Jesus Christ, thy Son our Lord, Who liveth and reigneth with thee, in the unity of the Holy Ghost, God, world without end. + ℟. Amen. +status: + la: verified + en: verified diff --git a/tests/calendar/day-label.test.ts b/tests/calendar/day-label.test.ts index 1cad7c1..9cc4bd3 100644 --- a/tests/calendar/day-label.test.ts +++ b/tests/calendar/day-label.test.ts @@ -27,7 +27,13 @@ describe('getDayLabel — ordinal temporal label', () => { }); it("Advent's own anchor Sunday is already week 1, not a separate anchor-week case", () => { - expect(getDayLabel(resolveDay('2025-11-30'))).toBe('The 1st Sunday of Advent'); + // 2025-11-30 is also St. Andrew's own day (Duplex II. classis) — since + // the November sanctoral pull, he's correctly commemorated alongside + // Advent I rather than simply absent (confirmed against the live + // reference engine, which shows the same pairing), so the label + // reflects both, feast name first, same pattern as Trinity Sunday's + // own St. Felix I case above. + expect(getDayLabel(resolveDay('2025-11-30'))).toBe('St. Andrew, Apostle — The 1st Sunday of Advent'); expect(getDayLabel(resolveDay('2025-12-01'))).toBe('Monday in the 1st week of Advent'); }); diff --git a/tests/calendar/november-sanctoral.test.ts b/tests/calendar/november-sanctoral.test.ts new file mode 100644 index 0000000..7dd687e --- /dev/null +++ b/tests/calendar/november-sanctoral.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, it } from 'vitest'; +import { resolveDay } from '../../src/calendar'; +import { getDayCollect } from '../../src/hours/resolve-common'; + +// Clean per-annum years for these dates (no Sunday collision) — see +// data/calendar/saints/*.yml for per-saint source detail. +describe('November sanctoral pull (first pass)', () => { + it('All Saints wins outright with a real proper collect, backfilled this month', () => { + const day = resolveDay('2025-11-01'); + expect(day.winner).toEqual({ kind: 'sanctoral', id: 'all-saints', name: 'All Saints', rank: 'duplex-1-classis' }); + expect(getDayCollect(day).status.en).toBe('verified'); + }); + + it('St. Martin of Tours wins outright at Duplex majus with a real proper collect and antiphon, over a genuinely unwinnable stub', () => { + const day = resolveDay('2025-11-11'); + expect(day.winner).toEqual({ + kind: 'sanctoral', + id: 'st-martin-of-tours', + name: 'St. Martin of Tours, Bishop and Confessor', + rank: 'duplex-majus', + }); + expect(day.commemorations).toEqual([ + { kind: 'sanctoral', id: 'st-menna', name: 'St. Menna, Martyr', rank: 'simplex' }, + ]); + expect(getDayCollect(day).status.en).toBe('verified'); + }); + + it('a monastic-calendar-specific reassignment (St. Emilian) displaces what the base Tridentine table gives to St. Martin I, Pope, who moves to a different date entirely', () => { + const emilianDay = resolveDay('2025-11-12'); + expect(emilianDay.winner).toEqual({ + kind: 'sanctoral', + id: 'st-emilian', + name: 'St. Emilian, Abbot', + rank: 'duplex', + }); + const martinIDay = resolveDay('2025-11-14'); + expect(martinIDay.winner).toEqual({ + kind: 'sanctoral', + id: 'st-martin-i', + name: 'St. Martin I, Pope and Martyr', + rank: 'semiduplex', + }); + }); + + it('All Saints of the Benedictine Order, a monastic-calendar-only addition absent from the base Tridentine table, wins outright at Duplex II. classis', () => { + const day = resolveDay('2025-11-13'); + expect(day.winner).toEqual({ + kind: 'sanctoral', + id: 'all-saints-of-the-benedictine-order', + name: 'All Saints of the Order of St. Benedict', + rank: 'duplex-2-classis', + }); + expect(day.commemorations).toEqual([]); + }); + + it('St. Clement transfers forward into St. Chrysogonus\'s day whenever his own date falls on a Sunday -- a single-day transfer this app models correctly, unlike August\'s multi-day-skip case', () => { + const clean = resolveDay('2032-11-24'); // Nov 23, 2032 is not a Sunday + expect(clean.winner).toEqual({ + kind: 'sanctoral', + id: 'st-chrysogonus', + name: 'St. Chrysogonus, Martyr', + rank: 'simplex', + }); + const transferred = resolveDay('2025-11-24'); // Nov 23, 2025 IS a Sunday + expect(transferred.winner).toEqual({ + kind: 'sanctoral', + id: 'st-clement', + name: 'St. Clement I, Pope and Martyr', + rank: 'semiduplex', + }); + expect(transferred.commemorations).toEqual([ + { kind: 'sanctoral', id: 'st-chrysogonus', name: 'St. Chrysogonus, Martyr', rank: 'simplex' }, + ]); + }); + + it('St. Andrew wins outright at Duplex II. classis with a real proper collect and antiphon, alone', () => { + const day = resolveDay('2026-11-30'); + expect(day.winner).toEqual({ + kind: 'sanctoral', + id: 'st-andrew', + name: 'St. Andrew, Apostle', + rank: 'duplex-2-classis', + }); + expect(day.commemorations).toEqual([]); + expect(getDayCollect(day).status.en).toBe('verified'); + }); +}); diff --git a/tests/hours/compline.test.ts b/tests/hours/compline.test.ts index bea9aa7..bd8186e 100644 --- a/tests/hours/compline.test.ts +++ b/tests/hours/compline.test.ts @@ -86,11 +86,13 @@ describe('resolveOrdo("compline", ...)', () => { }); it('anticipates Advent I: the Saturday evening before switches to the Alma Redemptoris Mater and shows the anticipated day label', () => { - // Nov 30, 2025 is Advent I Sunday. + // Nov 30, 2025 is Advent I Sunday -- also St. Andrew's own day + // (Duplex II. classis), correctly commemorated alongside it since the + // November sanctoral pull (see tests/calendar/day-label.test.ts). const eve = resolveOrdo('compline', '2025-11-29'); const last = eve.parts[eve.parts.length - 1]; expect(last?.kind === 'preces' ? last.label : undefined).toBe('Alma Redemptoris Mater'); - expect(eve.dayLabel).toBe('The 1st Sunday of Advent'); + expect(eve.dayLabel).toBe('St. Andrew, Apostle — The 1st Sunday of Advent'); const dayBefore = resolveOrdo('compline', '2025-11-28'); const lastBefore = dayBefore.parts[dayBefore.parts.length - 1];