Give Advent Sundays their own Matins Nocturn I-III content
Deploy / deploy (push) Successful in 1m27s
Deploy / deploy (push) Successful in 1m27s
Nocturns I-II had no seasonal override mechanism at all, and Nocturn III's own Septuagesima-Palm override didn't cover Advent — live-verified against the reference engine that Advent has its own seasonal antiphons/versicles across all three nocturns, identical on all 4 Advent Sundays. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017XMSokiTD2Qc5vPP2YQu3Q
This commit is contained in:
@@ -4549,3 +4549,30 @@ Re-verifying live (one `prayMatutinum` query per Sunday of the 2026 cycle, Monas
|
|||||||
New regression tests in `tests/hours/matins.test.ts` cover all three shapes (antiphon-only,
|
New regression tests in `tests/hours/matins.test.ts` cover all three shapes (antiphon-only,
|
||||||
antiphon+canticles+versicle, antiphon+versicle-only). `npm test` (817 passed), `tsc --noEmit`,
|
antiphon+canticles+versicle, antiphon+versicle-only). `npm test` (817 passed), `tsc --noEmit`,
|
||||||
and `npm run build` all pass.
|
and `npm run build` all pass.
|
||||||
|
|
||||||
|
### Advent Sunday Matins Nocturns I-III seasonal override (2026-09-01)
|
||||||
|
|
||||||
|
Follow-up, same day: the user asked whether Advent Sundays' own Nocturn III needed the same kind
|
||||||
|
of fix. Live re-check (`prayMatutinum`, Monastic Tridentinum 1617, all 4 Advent Sundays of the
|
||||||
|
2026 cycle) found the answer is yes, and bigger than just Nocturn III — Advent's own seasonal
|
||||||
|
antiphons apply to **all three nocturns**, not just Nocturn III, and identically across all 4
|
||||||
|
Sundays (no per-Sunday variation the way Septuagesima-Palm has).
|
||||||
|
|
||||||
|
- **Nocturns I-II**: psalm numbers unchanged (Ps 20-31), but every one of the 6 antiphons and
|
||||||
|
both versicles are seasonal — none of which existed anywhere in the codebase before this fix
|
||||||
|
(unlike Nocturn III, Nocturns I/II had *no* override mechanism at all; `matins.ts` used the
|
||||||
|
plain-season `matins-sunday-antiphons.yml` base unconditionally).
|
||||||
|
- **Nocturn III**: swaps the plain-season 3-canticle set (Isa 33:2-10/33:13-18, Sir 36:14-19) for
|
||||||
|
a wholly different one (Isa 40:10-17, 42:10-16, 49:7-13 — 3 new `data/scripture/isa-{40,42,49}.yml`
|
||||||
|
files), under its own Marian antiphon ("Gábriel Ángelus locútus est Maríæ...") and versicle.
|
||||||
|
|
||||||
|
New `data/hours/matins-sunday-advent-nocturn-overrides.yml` — a single season-wide block (keyed
|
||||||
|
by season, not per-Sunday `temporalId`, since all 4 Advent Sundays are identical) — plus
|
||||||
|
`hours/matins.ts`'s generalized `sundayNocturnFor(nocturn, day, temporalId)`, which now checks
|
||||||
|
Advent's season-wide override ahead of (Nocturn III only) the existing per-Sunday Septuagesima-
|
||||||
|
Palm `sundayNocturn3For` lookup; Advent and Septuagesima-Palm never overlap so there's no
|
||||||
|
precedence conflict between the two override tiers.
|
||||||
|
|
||||||
|
New regression test in `tests/hours/matins.test.ts` (`Advent Sunday Nocturns I-III seasonal
|
||||||
|
override`) asserts all 4 Advent Sundays render identically. `npm test` (818 passed),
|
||||||
|
`tsc --noEmit`, and `npm run build` all pass.
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# Sunday Matins Nocturns I-III, Advent override. Unlike
|
||||||
|
# matins-sunday-nocturn3-overrides.yml (keyed per-Sunday, Septuagesima
|
||||||
|
# through Palm Sunday, each Sunday distinct), this is a single season-wide
|
||||||
|
# block applied uniformly to all 4 Advent Sundays — live-verified
|
||||||
|
# identical across advent-1..4 (2026 cycle dates 11-29, 12-06, 12-13,
|
||||||
|
# 12-20) against the local reference-engine CGI instance (`prayMatutinum`,
|
||||||
|
# Monastic Tridentinum 1617, 2026-09-01).
|
||||||
|
#
|
||||||
|
# Unlike the existing Nocturn III-only override, Advent replaces the
|
||||||
|
# antiphon *and* versicle of all three nocturns (psalm/canticle numbers
|
||||||
|
# unchanged for Nocturns I-II, Ps 20-31; Nocturn III swaps its plain-season
|
||||||
|
# 3-canticle set for a wholly different one, Isa 40:10-17 / 42:10-16 /
|
||||||
|
# 49:7-13 — new scripture chapter files authored alongside this one).
|
||||||
|
#
|
||||||
|
# hours/matins.ts's lookup applies this whenever day.season === 'advent',
|
||||||
|
# ahead of (and instead of, since Advent and Septuagesima-Palm never
|
||||||
|
# overlap) the temporalId-keyed Nocturn III override.
|
||||||
|
|
||||||
|
nocturn1:
|
||||||
|
groups:
|
||||||
|
- psalms: [20, 21]
|
||||||
|
antiphon:
|
||||||
|
la: "Véniet ecce rex, excélsus cum potestáte magna, ad salvándas gentes, allelúja."
|
||||||
|
en: "Behold, there cometh the King, the Most High, with great power, to save the nations, alleluia."
|
||||||
|
- psalms: [22, 23]
|
||||||
|
antiphon:
|
||||||
|
la: "Confortáte manus dissolútas: confortámini, dícite: Ecce Deus noster véniet, et salvábit nos, allelúja."
|
||||||
|
en: "Strengthen ye the weak hands; be strong, say: Behold, our God will come, and save us, alleluia."
|
||||||
|
- psalms: [24, 25]
|
||||||
|
antiphon:
|
||||||
|
la: "Gaudéte omnes et lætámini: ecce, qui véniet Dóminus ultiónis, addúcet retributiónem: ipse véniet, et salvábit nos."
|
||||||
|
en: "Rejoice all ye, and be glad; for behold, the Lord will come with vengeance, He will bring a recompense; He will come and save us."
|
||||||
|
versicle:
|
||||||
|
v: { la: "Ex Sion spécies decóris ejus.", en: "From Sion, from the place of his greatness." }
|
||||||
|
r: { la: "Deus noster maniféste véniet.", en: "Our God shall come manifestly." }
|
||||||
|
|
||||||
|
nocturn2:
|
||||||
|
groups:
|
||||||
|
- psalms: [26, 27]
|
||||||
|
antiphon:
|
||||||
|
la: "Gaude et lætáre fília Jerúsalem: ecce, Rex tuus véniet tibi: Sion noli timére, qui cito véniet salus tua."
|
||||||
|
en: "Rejoice greatly, O daughter of Jerusalem: behold, thy King cometh into thee, O Zion; fear not, for thy salvation cometh quickly."
|
||||||
|
- psalms: [28, 29]
|
||||||
|
antiphon:
|
||||||
|
la: "Rex noster advéniet Christus, quem Joánnes prædicávit Agnum esse ventúrum."
|
||||||
|
en: "Christ our King cometh, Whom John preached, saying: Behold the Lamb That should come!"
|
||||||
|
- psalms: [30, 31]
|
||||||
|
antiphon:
|
||||||
|
la: "Ecce, vénio cito et merces mea mecum est, dicit Dóminus: dare unicuíque secúndum ópera sua."
|
||||||
|
en: "Behold, I come quickly, saith the Lord, and My reward is with Me, to give every man according as his work shall be."
|
||||||
|
versicle:
|
||||||
|
v: { la: "Emítte Agnum, Dómine, Dominatórem terræ.", en: "Send forth, O Lord, the lamb, the ruler of the earth." }
|
||||||
|
r: { la: "De Petra desérti ad montem fíliæ Sion.", en: "From Petra of the desert, to the mount of the daughter of Sion." }
|
||||||
|
|
||||||
|
nocturn3:
|
||||||
|
canticles:
|
||||||
|
- refs: [{ book: isa, chapter: 40, verses: "10-17" }]
|
||||||
|
- refs: [{ book: isa, chapter: 42, verses: "10-16" }]
|
||||||
|
- refs: [{ book: isa, chapter: 49, verses: "7-13" }]
|
||||||
|
antiphon:
|
||||||
|
la: "Gábriel Ángelus locútus est Maríæ, dicens: Ave, grátia plena; Dóminus tecum; Benedícta tu in mulíeres."
|
||||||
|
en: "The Angel Gabriel spake unto Mary, saying: Hail, thou that art full of grace, the Lord is with thee: blessed art thou among women."
|
||||||
|
versicle:
|
||||||
|
v: { la: "Egrediétur Dóminus de loco sancto suo.", en: "The Lord will come out of his holy place." }
|
||||||
|
r: { la: "Véniet ut salvet pópulum suum.", en: "He will come to save his people." }
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# Isaiah 40 — verses 10-17 transcribed from a live Divinum Officium query
|
||||||
|
# (Monastic Tridentinum 1617, prayMatutinum, 2026-09-01, all 4 Advent
|
||||||
|
# Sundays of the 2026 cycle — identical content on each) — see
|
||||||
|
# data/hours/matins-sunday-advent-nocturn-overrides.yml. Only the verse
|
||||||
|
# range actually used by that Nocturn III canticle is authored; the rest
|
||||||
|
# of the chapter is unauthored (empty per src/scripture's own
|
||||||
|
# "unauthored -> not present" convention).
|
||||||
|
book: isa
|
||||||
|
chapter: 40
|
||||||
|
verses:
|
||||||
|
- n: 10
|
||||||
|
text:
|
||||||
|
la: "Ecce Dóminus Deus in fortitúdine véniet, * et bráchium ejus dominábitur:"
|
||||||
|
en: "Behold the Lord God shall come with strength, * and his arm shall rule:"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 10
|
||||||
|
text:
|
||||||
|
la: "Ecce merces ejus cum eo, * et opus illíus coram illo."
|
||||||
|
en: "Behold his reward is with him * and his work is before him."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 11
|
||||||
|
text:
|
||||||
|
la: "Sicut pastor gregem suum pascet: in bráchio suo congregábit agnos, * et in sinu suo levábit, fœtas ipse portábit."
|
||||||
|
en: "He shall feed his flock like a shepherd: he shall gather together the lambs with his arm, * and shall take them up in his bosom, and he himself shall carry them that are with young."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 12
|
||||||
|
text:
|
||||||
|
la: "Quis mensus est pugíllo aquas, * et cælos palmo ponderávit?"
|
||||||
|
en: "Who hath measured the waters * in the hollow of his hand, and weighed the heavens with his palm?"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 12
|
||||||
|
text:
|
||||||
|
la: "Quis appéndit tribus dígitis molem terræ, * et librávit in póndere montes, et colles in statéra?"
|
||||||
|
en: "Who hath poised with three fingers the bulk of the earth, * and weighed the mountains in scales, and the hills in a balance?"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 13
|
||||||
|
text:
|
||||||
|
la: "Quis adjúvit spíritum Dómini? * aut quis consiliárius ejus fuit, et osténdit illi?"
|
||||||
|
en: "Who hath forwarded the spirit of the Lord? * or who hath been his counsellor, and hath taught him?"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 14
|
||||||
|
text:
|
||||||
|
la: "Cum quo íniit consílium, et instrúxit eum, et dócuit eum sémitam justítiæ, * et erudívit eum sciéntiam, et viam prudéntiæ osténdit illi?"
|
||||||
|
en: "With whom hath he consulted, and who hath instructed him, and taught him the path of justice, * and taught him knowledge, and shewed him the way of understanding?"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 15
|
||||||
|
text:
|
||||||
|
la: "Ecce gentes quasi stilla sítulæ, * et quasi moméntum statéræ reputátæ sunt:"
|
||||||
|
en: "Behold the Gentiles are as a drop of a bucket, * and are counted as the smallest grain of a balance."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 16
|
||||||
|
text:
|
||||||
|
la: "Ecce ínsulæ quasi pulvis exíguus. Et Líbanus non suffíciet ad succendéndum, * et animália ejus non suffícient ad holocáustum."
|
||||||
|
en: "Behold the islands are as a little dust. And Libanus shall not be enough to burn, * nor the beasts thereof sufficient for a burnt offering."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 17
|
||||||
|
text:
|
||||||
|
la: "Omnes gentes quasi non sint, sic sunt coram eo, * et quasi níhilum et ináne reputátæ sunt ei."
|
||||||
|
en: "All nations are before him as if they had no being at all, * and are counted to him as nothing, and vanity."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Isaiah 42 — verses 10-16 transcribed from a live Divinum Officium query
|
||||||
|
# (Monastic Tridentinum 1617, prayMatutinum, 2026-09-01, all 4 Advent
|
||||||
|
# Sundays of the 2026 cycle — identical content on each) — see
|
||||||
|
# data/hours/matins-sunday-advent-nocturn-overrides.yml. Only the verse
|
||||||
|
# range actually used by that Nocturn III canticle is authored.
|
||||||
|
book: isa
|
||||||
|
chapter: 42
|
||||||
|
verses:
|
||||||
|
- n: 10
|
||||||
|
text:
|
||||||
|
la: "Cantáte Dómino cánticum novum, * laus ejus ab extrémis terræ,"
|
||||||
|
en: "Sing ye to the Lord a new song, * his praise is from the ends of the earth."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 10
|
||||||
|
text:
|
||||||
|
la: "Qui descénditis in mare, et plenitúdo ejus: * ínsulæ, et habitatóres eárum."
|
||||||
|
en: "You that go down to the sea, and all that are therein: * ye islands, and ye inhabitants of them."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 11
|
||||||
|
text:
|
||||||
|
la: "Sublevétur desértum et civitátes ejus * in dómibus habitábit Cedar."
|
||||||
|
en: "Let the desert and the cities thereof be exalted: * Cedar shall dwell in houses:"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 11
|
||||||
|
text:
|
||||||
|
la: "Laudáte, habitatóres Petræ: * de vértice móntium clamábunt."
|
||||||
|
en: "Ye inhabitants of Petra, give praise, * they shall cry from the top of the mountains."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 12
|
||||||
|
text:
|
||||||
|
la: "Ponent Dómino glóriam, * et laudem ejus in ínsulis nuntiábunt."
|
||||||
|
en: "They shall give glory to the Lord, * and shall declare his praise in the islands."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 13
|
||||||
|
text:
|
||||||
|
la: "Dóminus sicut fortis egrediétur, * sicut vir prœliátor suscitábit zelum:"
|
||||||
|
en: "The Lord shall go forth as a mighty man, * as a man of war shall he stir up zeal."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 13
|
||||||
|
text:
|
||||||
|
la: "Vociferábitur, et clamábit: * super inimícos suos confortábitur."
|
||||||
|
en: "He shall shout and cry: * he shall prevail against his enemies."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 14
|
||||||
|
text:
|
||||||
|
la: "Tácui semper, sílui, pátiens fui: * sicut partúriens loquar."
|
||||||
|
en: "I have always held my peace, I have kept silence, I have been patient, * I will speak now as a woman in labour."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 14
|
||||||
|
text:
|
||||||
|
la: "Dissipábo, et absorbébo simul. * desértos fáciam montes et colles, et omne gramen eórum exsiccábo."
|
||||||
|
en: "I will destroy, and swallow up at once. * I will lay waste the mountains and hills, and will make all their grass to wither."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 15
|
||||||
|
text:
|
||||||
|
la: "Et ponam flúmina in ínsulas, * et stagna arefáciam."
|
||||||
|
en: "And I will turn rivers into islands, * and will dry up the standing pools."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 16
|
||||||
|
text:
|
||||||
|
la: "Et ducam cæcos in viam quam nésciunt, * et in sémitis quas ignoravérunt ambuláre eos fáciam."
|
||||||
|
en: "And I will lead the blind into the way which they know not: * and in the paths which they were ignorant of I will make them walk."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 16
|
||||||
|
text:
|
||||||
|
la: "Ponam ténebras coram eis in lucem, * et prava in recta."
|
||||||
|
en: "I will make darkness light before them, * and crooked things straight."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# Isaiah 49 — verses 7-13 transcribed from a live Divinum Officium query
|
||||||
|
# (Monastic Tridentinum 1617, prayMatutinum, 2026-09-01, all 4 Advent
|
||||||
|
# Sundays of the 2026 cycle — identical content on each) — see
|
||||||
|
# data/hours/matins-sunday-advent-nocturn-overrides.yml. Only the verse
|
||||||
|
# range actually used by that Nocturn III canticle is authored.
|
||||||
|
book: isa
|
||||||
|
chapter: 49
|
||||||
|
verses:
|
||||||
|
- n: 7
|
||||||
|
text:
|
||||||
|
la: "Hæc dicit Dóminus redémptor Israël, sanctus ejus, ad contemptíbilem ánimam, * ad abominátam gentem, ad servum dominórum."
|
||||||
|
en: "Thus saith the Lord the redeemer of Israel, his Holy One, to the soul that is despised, * to the nation that is abhorred, to the servant of rulers."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 7
|
||||||
|
text:
|
||||||
|
la: "Reges vidébunt, et consúrgent príncipes, et adorábunt propter Dóminum, quia fidélis est, * et sanctum Israël qui elégit te."
|
||||||
|
en: "Kings shall see, and princes shall rise up, and adore for the Lord’s sake, because he is faithful, * and for the Holy One of Israel, who hath chosen thee."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 8
|
||||||
|
text:
|
||||||
|
la: "Hæc dicit Dóminus: In témpore plácito exaudívi te, * et in die salútis auxiliátus sum tui."
|
||||||
|
en: "Thus saith the Lord: In an acceptable time I have heard thee, * and in the day of salvation I have helped thee."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 8
|
||||||
|
text:
|
||||||
|
la: "Et servávi te, et dedi te in fœdus pópuli, * ut suscitáres terram, et possidéres hereditátes dissipátas:"
|
||||||
|
en: "And I have preserved thee, and given thee to be a covenant of the people, * that thou mightest raise up the earth, and possess the inheritances that were destroyed:"
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 9
|
||||||
|
text:
|
||||||
|
la: "Ut díceres his qui vincti sunt: exíte, * et his qui in ténebris: revelámini."
|
||||||
|
en: "That thou mightest say to them that are bound: Come forth: * and to them that are in darkness: Shew yourselves."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 9
|
||||||
|
text:
|
||||||
|
la: "Super vias pascéntur, * et in ómnibus planis páscua eórum."
|
||||||
|
en: "They shall feed in the ways, * and their pastures shall be in every plain."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 10
|
||||||
|
text:
|
||||||
|
la: "Non esúrient neque sítient, et non percútiet eos æstus et sol, * quia miserátor eórum reget eos, et ad fontes aquárum potábit eos."
|
||||||
|
en: "They shall not hunger, nor thirst, neither shall the heat nor the sun strike them: * for he that is merciful to them, shall be their shepherd, and at the fountains of waters he shall give them drink."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 11
|
||||||
|
text:
|
||||||
|
la: "Et ponam omnes montes meos in viam, * et sémitæ meæ exaltabúntur."
|
||||||
|
en: "And I will make all my mountains a way, * and my paths shall be exalted."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 12
|
||||||
|
text:
|
||||||
|
la: "Ecce isti de longe vénient, et ecce illi ab aquilóne et mari, * et isti de terra austráli."
|
||||||
|
en: "Behold these shall come from afar, and behold these from the north and from the sea, * and these from the south country."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
|
- n: 13
|
||||||
|
text:
|
||||||
|
la: "Laudáte cæli, et exsúlta terra, jubiláte montes laudem: * quia consolátus est Dóminus pópulum suum, et páuperum suórum miserébitur."
|
||||||
|
en: "Give praise, O ye heavens, and rejoice, O earth, ye mountains, give praise with jubilation: * because the Lord hath comforted his people, and will have mercy on his poor ones."
|
||||||
|
status: { la: verified, en: verified }
|
||||||
+33
-3
@@ -95,6 +95,7 @@ import { getOctaveReading } from '../propers/octave-readings';
|
|||||||
import { getMatinsSaintOverride, getMatinsCommonOverride, type MatinsPsalmodyScheme } from './matins-psalmody-overrides';
|
import { getMatinsSaintOverride, getMatinsCommonOverride, type MatinsPsalmodyScheme } from './matins-psalmody-overrides';
|
||||||
import matinsSundayAntiphonsData from '../data/hours/matins-sunday-antiphons.yml';
|
import matinsSundayAntiphonsData from '../data/hours/matins-sunday-antiphons.yml';
|
||||||
import matinsSundayNocturn3OverridesData from '../data/hours/matins-sunday-nocturn3-overrides.yml';
|
import matinsSundayNocturn3OverridesData from '../data/hours/matins-sunday-nocturn3-overrides.yml';
|
||||||
|
import matinsSundayAdventOverridesData from '../data/hours/matins-sunday-advent-nocturn-overrides.yml';
|
||||||
import matinsFerialAntiphonsData from '../data/hours/matins-ferial-antiphons.yml';
|
import matinsFerialAntiphonsData from '../data/hours/matins-ferial-antiphons.yml';
|
||||||
import type { Weekday } from '../calendar/types';
|
import type { Weekday } from '../calendar/types';
|
||||||
|
|
||||||
@@ -145,6 +146,35 @@ function sundayNocturn3For(temporalId: string | undefined): SundayNocturn {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Advent's own Nocturns I-III override, applied uniformly across all 4
|
||||||
|
// Advent Sundays (unlike sundayNocturn3Overrides above, which is keyed
|
||||||
|
// per-distinct-Sunday for Septuagesima-Palm) — see
|
||||||
|
// data/hours/matins-sunday-advent-nocturn-overrides.yml's own header.
|
||||||
|
interface MatinsSundayAdventOverrides {
|
||||||
|
nocturn1: Partial<SundayNocturn>;
|
||||||
|
nocturn2: Partial<SundayNocturn>;
|
||||||
|
nocturn3: Partial<SundayNocturn>;
|
||||||
|
}
|
||||||
|
const sundayAdventOverrides = matinsSundayAdventOverridesData as unknown as MatinsSundayAdventOverrides;
|
||||||
|
|
||||||
|
/** Sunday Nocturn I/II/III content for a given day — Advent's own
|
||||||
|
* season-wide override (all three nocturns) takes precedence over the
|
||||||
|
* plain-season default; Nocturn III additionally checks the per-Sunday
|
||||||
|
* Septuagesima-Palm override (`sundayNocturn3For`) when Advent doesn't
|
||||||
|
* apply (the two never overlap). */
|
||||||
|
function sundayNocturnFor(nocturnKey: 'nocturn1' | 'nocturn2' | 'nocturn3', day: LiturgicalDay, temporalId: string | undefined): SundayNocturn {
|
||||||
|
const base = nocturnKey === 'nocturn3' ? sundayNocturn3For(temporalId) : sundayAntiphons[nocturnKey];
|
||||||
|
if (day.season !== 'advent') return base;
|
||||||
|
const override = sundayAdventOverrides[nocturnKey];
|
||||||
|
if (!override) return base;
|
||||||
|
return {
|
||||||
|
groups: override.groups ?? base.groups,
|
||||||
|
canticles: override.canticles ?? base.canticles,
|
||||||
|
antiphon: override.antiphon ?? base.antiphon,
|
||||||
|
versicle: override.versicle ?? base.versicle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface FerialGroup {
|
interface FerialGroup {
|
||||||
psalms: PsalmRef[];
|
psalms: PsalmRef[];
|
||||||
antiphon: BilingualText;
|
antiphon: BilingualText;
|
||||||
@@ -704,13 +734,13 @@ export function resolveOrdo(date: string): ResolvedOrdo {
|
|||||||
|
|
||||||
if (threeNocturns && day.weekday === 'sunday') {
|
if (threeNocturns && day.weekday === 'sunday') {
|
||||||
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
||||||
parts.push(...sundayPsalmNocturn(sundayAntiphons.nocturn1, day));
|
parts.push(...sundayPsalmNocturn(sundayNocturnFor('nocturn1', day, temporalId), day));
|
||||||
parts.push(...(nocturn1Readings ?? []));
|
parts.push(...(nocturn1Readings ?? []));
|
||||||
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[1]}` });
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[1]}` });
|
||||||
parts.push(...sundayPsalmNocturn(sundayAntiphons.nocturn2, day));
|
parts.push(...sundayPsalmNocturn(sundayNocturnFor('nocturn2', day, temporalId), day));
|
||||||
parts.push(...(nocturn2Readings ?? []));
|
parts.push(...(nocturn2Readings ?? []));
|
||||||
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[2]}` });
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[2]}` });
|
||||||
parts.push(...sundayCanticleNocturn(sundayNocturn3For(temporalId), day));
|
parts.push(...sundayCanticleNocturn(sundayNocturnFor('nocturn3', day, temporalId), day));
|
||||||
parts.push(...(nocturn3Readings ?? []));
|
parts.push(...(nocturn3Readings ?? []));
|
||||||
parts.push({ kind: 'te-deum', text: resolveCommon('te-deum') });
|
parts.push({ kind: 'te-deum', text: resolveCommon('te-deum') });
|
||||||
parts.push({ kind: 'versicle', text: resolveCommon('te-decet-laus') });
|
parts.push({ kind: 'versicle', text: resolveCommon('te-decet-laus') });
|
||||||
|
|||||||
@@ -237,6 +237,42 @@ describe('resolveOrdo("matins", ...) Sunday Nocturn III seasonal override (2026-
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Real bug (found 2026-09-01, same shape as the Nocturn III fix above, but
|
||||||
|
// bigger: Advent Sundays' Nocturns I-II antiphons/versicles are also
|
||||||
|
// seasonal, not just Nocturn III's antiphon+canticles+versicle — live-
|
||||||
|
// verified against the reference engine (Monastic Tridentinum 1617),
|
||||||
|
// identical across all 4 Advent Sundays of the 2026 cycle.
|
||||||
|
describe('resolveOrdo("matins", ...) Advent Sunday Nocturns I-III seasonal override (2026-09-01 fix)', () => {
|
||||||
|
it('all 4 Advent Sundays render identical seasonal content (Nocturns I-III antiphons/versicles, Nocturn III canticles)', () => {
|
||||||
|
const dates = ['2026-11-29', '2026-12-06', '2026-12-13', '2026-12-20'];
|
||||||
|
const renders = dates.map((date) => resolveOrdo('matins', date));
|
||||||
|
|
||||||
|
for (const ordo of renders) {
|
||||||
|
const psalms = ordo.parts.filter((p) => p.kind === 'psalm').map((p) => (p as { psalmNumber: number }).psalmNumber);
|
||||||
|
expect(psalms).toEqual([3, 94, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]);
|
||||||
|
const canticles = ordo.parts.filter((p) => p.kind === 'canticle') as { canticleId: string }[];
|
||||||
|
expect(canticles.map((c) => c.canticleId)).toEqual(['isa-40-10-17', 'isa-42-10-16', 'isa-49-7-13']);
|
||||||
|
|
||||||
|
const antiphons = ordo.parts.filter((p) => p.kind === 'antiphon') as { text: { text: Record<string, string> } }[];
|
||||||
|
expect(antiphons.at(-1)?.text.text.la).toBe(
|
||||||
|
'Ant. Gábriel Ángelus locútus est Maríæ, dicens: Ave, grátia plena; Dóminus tecum; Benedícta tu in mulíeres.',
|
||||||
|
);
|
||||||
|
|
||||||
|
const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[];
|
||||||
|
const [, nocturn1, nocturn2, nocturn3] = versicles;
|
||||||
|
expect(nocturn1?.text.text.la).toBe('V. Ex Sion spécies decóris ejus.\nR. Deus noster maniféste véniet.');
|
||||||
|
expect(nocturn2?.text.text.la).toBe('V. Emítte Agnum, Dómine, Dominatórem terræ.\nR. De Petra desérti ad montem fíliæ Sion.');
|
||||||
|
expect(nocturn3?.text.text.la).toBe('V. Egrediétur Dóminus de loco sancto suo.\nR. Véniet ut salvet pópulum suum.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same content on every one of the 4 Sundays, not just individually correct.
|
||||||
|
const nocturn1Openings = renders.map(
|
||||||
|
(ordo) => (ordo.parts.filter((p) => p.kind === 'antiphon')[1] as { text: { text: Record<string, string> } }).text.text.la,
|
||||||
|
);
|
||||||
|
expect(new Set(nocturn1Openings).size).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('resolveOrdo("matins", ...) Duplex+ weekday-feast (3-nocturn, non-Sunday) branch', () => {
|
describe('resolveOrdo("matins", ...) Duplex+ weekday-feast (3-nocturn, non-Sunday) branch', () => {
|
||||||
// 2026-08-17 -- St. Lawrence's own octave closing day ("In Octava S.
|
// 2026-08-17 -- St. Lawrence's own octave closing day ("In Octava S.
|
||||||
// Laurentii Martyris ~ Duplex"), live-verified directly against the
|
// Laurentii Martyris ~ Duplex"), live-verified directly against the
|
||||||
|
|||||||
Reference in New Issue
Block a user