Compare commits

..

5 Commits

Author SHA1 Message Date
will 359c7bfc49 Log the seasonal hymn-doxology work in TODO.md
Deploy / deploy (push) Successful in 2m2s
Closes the "unexamined gap" open-work item and records both passes (the
source-marker audit, then the deliberate broadening) as dated build-log
entries, including the extraction-script bug caught and reverted before
anything was committed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGjUyhUZJaSjiniEmnLdak
2026-09-03 15:00:26 -04:00
will 46b34493e2 Wire seasonal hymn-doxology into every plain-default Lauds hymn
Lauds' Monastic source never carries the "*" substitution marker anywhere
(audited), so this is purely the same deliberate broadening as the Vespers
commit: every plain-default hymn (Sunday, Mon-Sat, Advent, Lent,
Passiontide, Paschaltide) now routes its closing doxology through
getHymnDoxologyId/appendDoxology instead of a fixed ending, split into
matching per-annum companion files that reproduce the original text
whenever no season/feast override applies.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGjUyhUZJaSjiniEmnLdak
2026-09-03 15:00:17 -04:00
will 0736c36494 Wire seasonal hymn-doxology into every plain-default Vespers hymn
Sunday's hymn ("Lucis Creator") is the one case whose Monastic source text
carries a real "*" seasonal-substitution marker (live-checked); every other
key (Mon-Sat, Advent, Lent, Passiontide, Paschaltide) is wired the same way
anyway as a deliberate broadening beyond the source, at the user's request
("the doxology is a neat way to stay tuned in to the season... we're doing a
remix, not a copy"). Each hymn's own natural ending is split into a matching
per-annum companion file, so a season/feast with no override reproduces the
original text exactly; only Nat/Epi/Pasch/Asc/Pent/Corp/Heart and the two
feast/date overrides from the previous commit actually change anything.

Real visible effect: hymns shown during Christmastide/Epiphanytide/Corpus
Christi/Sacred Heart (none of which get a distinct seasonal hymn, so these
were always the plain weekday defaults) now pick up the right doxology
instead of a generic ending; Ascensiontide and the Pentecost octave now
diverge from the rest of Paschaltide's doxology mid-season.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGjUyhUZJaSjiniEmnLdak
2026-09-03 15:00:06 -04:00
will aeda043577 Wire seasonal hymn-doxology into the Matins ferial hymn
The plain ferial hymn's Monastic source (Day1-6 Hymnus,
Psalterium/Special/Matutinum Special.txt) carries a real "*" seasonal-
substitution marker, live-checked against the reference engine. Splits the
hymn's own natural doxology ending into a new per-annum companion file and
swaps it via getHymnDoxologyId/appendDoxology, same pattern already used by
Prime and Compline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGjUyhUZJaSjiniEmnLdak
2026-09-03 14:59:49 -04:00
will 44feb8c6b1 Widen seasonal hymn-doxology to cover Marian Saturday and the Assumption octave
getHymnDoxologyId now takes the whole LiturgicalDay (needed for a date-window
check) and checks a feast override for a temporal winner's id too, not just
sanctoral — matching Divinum Officium's own Common-of-the-BVM `Doxology=Nat`
rule, which is why Marian Saturdays get the Nativity doxology regardless of
season. Also ports the source's Aug 16-22 (Assumption octave) hardcoded
Nativity-doxology window, confirmed live not excluded for the Monastic/
Tridentine 1617 track.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGjUyhUZJaSjiniEmnLdak
2026-09-03 14:59:32 -04:00
54 changed files with 393 additions and 316 deletions
+86 -11
View File
@@ -22,17 +22,6 @@ across every hour and content type in this app.
- Paschaltide should substitute the ordinary suffrages/ferial-Preces set with a single
alleluia-form "Suffragium Paschale" — not modeled; the ordinary set is shown unchanged
throughout Paschaltide instead.
- Seasonal hymn-doxology swap (`hours/hymn-doxology.ts`'s `getHymnDoxologyId`/
`appendDoxology`) is only wired into **Prime and Compline** (checked 2026-09-03:
`grep -c getHymnDoxologyId` is 0 for `lauds.ts`/`vespers.ts`/`matins.ts`). Terce/Sext/None
are confirmed fine as-is — their hymn is genuinely self-contained with no seasonal swap in
the source (see `terce.yml`'s own header). Lauds, Vespers, and Matins are the real,
unexamined gap: every hymn there is stored as one fixed text captured on its proof date,
with no check yet done on whether the source actually varies its closing doxology by
season the way Prime/Compline's does — this was previously logged as a narrow "5 of 30
Vespers hymns" simplification, but that undersold it; nothing rules out Lauds/Matins
having the same issue. Needs a per-hour audit against the reference engine before either
wiring in the existing mechanism or confirming (like Terce) that no swap is needed.
2. **Minimal-proof-done, bulk content pending** — mechanism is built and trusted (a proof
date/entry already resolves correctly end-to-end); what's left is authoring/importing more
@@ -5033,3 +5022,89 @@ the pre-existing `isa-33`/`sir-36` pointing-split half-verses (same convention,
cause).
`npm test` (2018 passed), `tsc --noEmit`, and `npm run build` all pass.
### Seasonal hymn-doxology swap — audited Lauds/Vespers/Matins, wired the two real gaps (2026-09-03, same day)
Closes the "unexamined gap" logged for Lauds/Vespers/Matins: the mechanism
(`hours/hymn-doxology.ts`) was previously wired only into Prime and Compline, with every
Lauds/Vespers/Matins hymn stored as one fixed text and no check done on whether the source
actually varies its closing doxology by season there.
Audited by exhaustively grepping every `[Hymnus ...]`/`[HymnusM ...]` section in Divinum
Officium's own `Psalterium/Special/{Major,Matutinum} Special.txt` for a real "*"
substitution marker (distinct from the unrelated antiphon-incipit "*" convention used
throughout responsory/antiphon text). The Monastic 1617 track (vu's own structural source)
turned out to carry the marker in exactly two places: Sunday's plain-default Vespers hymn
("Lucis Creator", inherited unchanged from the base secular text via a `@:`-reference with
unrelated wording substitutions) and the plain ferial Matins hymn (Day1-6, all six weekday
forms share it). Every other hymn checked — Sunday Lauds, the Mon-Sat Lauds/Vespers weekday
defaults, the Advent Lauds/Vespers/Matins hymns, and (initially assumed to need this) the
Monastic Paschaltide Lauds/Vespers/Matins hymns specifically — has its own fixed,
non-swapping doxology already baked into the text in the source itself. This generalizes
Terce/Sext/None's already-confirmed "self-contained, no swap" finding without making it
universal — Lauds needed no wiring at all as a result.
Wired the two real cases via `getHymnDoxologyId(day, perAnnumId)` (signature changed from
`(season, winner, perAnnumId)` to take the whole `LiturgicalDay`, needed for the date-window
check below) into `vespers.ts`'s new `resolveVespersHymn` helper and `matins.ts`'s
`resolveMatinsHymn` fallback tier. New `vespers-hymn-doxology-per-annum.yml`/
`matins-hymn-doxology-per-annum.yml` hold each hymn's own natural per-annum ending, split out
of `vespers-hymn-sunday.yml`/`matins-hymn-ferial.yml`.
Also closed two related real gaps found during the same source audit, both live-checked
against `hymni.pl`'s `doxology()` sub (the mechanism this project's own hymn-doxology.ts is
modeled on):
- The Common of the BVM's own `Doxology=Nat` rule (`Commune/C10.txt` through `C12Q.txt`) means
Marian Saturdays get the Nativity doxology regardless of season, not just during
Christmastide/Epiphanytide — `hymn-doxology-by-feast.yml`'s `byFeastId` now has a
`marian-saturday` entry, and `resolveOfficeWinner`'s feast-override check in
`getHymnDoxologyId` now looks up a `kind: 'temporal'` winner's id too, not just
`'sanctoral'` (a temporal id and a sanctoral id never collide, so this is safe to check
unconditionally).
- The Assumption's octave (Aug 16-22) is hardcoded in the source to the Nativity doxology
regardless of season or the day's own winner — confirmed *not* excluded for the 1570/1617
track (unlike its Dec 9-15 companion rule for the Immaculate Conception's run-up, which the
source explicitly excludes 1617 from, so that one was deliberately left unported). Checked
directly by date (`isAssumptionOctaveWindow`), same pattern as `marian-antiphon.ts`'s
`isCandlemasToHolyWednesday` — this window doesn't line up with any `Season` value.
`npm test` (2021 passed) and `tsc --noEmit` both pass.
### Seasonal hymn-doxology swap, take two — broadened beyond the source's own marker (2026-09-03, same day)
Follow-up to the entry above, at the user's explicit direction: "the doxology is a neat way to
stay tuned in to the season... we're doing a remix, not a copy." The first pass wired the
mechanism only where the Monastic source itself carries a real "*" substitution marker (two
spots total). This pass wires it into *every* plain-default Lauds/Vespers hymn (Sunday,
Mon-Sat, Advent, Lent, Passiontide, Paschaltide — 21 files total, all but the two already done)
regardless of whether the source swaps that specific hymn, matching this project's own
"Not a reconstruction" stance (repo `CLAUDE.md`) rather than the reference engine's literal
behavior.
Each hymn file's own natural per-annum ending was split out into a matching
`{hour}-hymn-{key}-doxology-per-annum.yml` (same convention as the first pass), so a
season/feast with no override (Advent, Lent — the source never swaps those, and nothing here
changes that) reproduces the exact original text; `lauds.ts`'s new `resolveLaudsHymn` and
`vespers.ts`'s widened `resolveVespersHymn` route every plain-default hymn through
`appendDoxology`/`getHymnDoxologyId` uniformly. The real, visible effect: hymns shown during
Christmastide/Epiphanytide/Corpus Christi/Sacred Heart (none of which `seasonalOfficeSuffix`
covers, so these were always the plain weekday-default hymns) now pick up the Nat/Epi/Corp/Heart
doxology instead of staying on their generic ending; Ascensiontide and the Pentecost octave now
correctly diverge from the rest of Paschaltide's "Pasch" doxology to their own "Asc"/"Pent" one
mid-season. Matins was left as before (only the ferial fallback wired, from the first pass) —
it has no per-weekday or per-season hymn files to broaden into; every other season there still
falls through to that same one ferial hymn already.
A first automated extraction pass had a real bug (a body/stanza-boundary parser that failed to
stop at `status:` when a hymn's English translation had one fewer stanza than its Latin — no
English doxology stanza was ever transcribed for several weekday hymns — silently swallowing
the YAML `status:` block into the hymn text) and was caught before being trusted: none of its
output was committed, all 20 affected originals were reverted via `git checkout` back to this
same day's untouched-by-that-bug state, and redone with a corrected parser plus manual
spot-checks of the regenerated files.
`npm test` (2021 passed) and `tsc --noEmit` both pass. Live-checked via a scratch test (not
committed) confirming Epiphanytide/Eastertide/Ascensiontide/Pentecost/Sacred-Heart plain days
now show the right doxology and Advent/Lent plain days are byte-identical to their pre-change
text.
+10 -4
View File
@@ -1,5 +1,11 @@
# Per-feast override of the hymn's doxology stanza — real Divinum Officium
# has a `winner{Doxology}` mechanism for this (some feasts specify their own).
# Empty until milestone 4's sanctoral propers store exists, same as
# prime-chapter-responsory-by-feast.yml.
byFeastId: {}
# has a `winner{Doxology}` mechanism for this (some feasts specify their own),
# plus a `Rule Doxology=` mechanism a whole Common can set (e.g. the Common
# of the BVM's own `Doxology=Nat` — Commune/C10-C12Q.txt, live-checked
# 2026-09-03), which is why marian-saturday is keyed here by its temporal id
# even though it's not a "feast" in the sanctoral-propers-store sense; see
# hours/hymn-doxology.ts's getHymnDoxologyId for the kind-agnostic lookup.
# Otherwise empty until milestone 4's sanctoral propers store exists, same
# as prime-chapter-responsory-by-feast.yml.
byFeastId:
marian-saturday: hymn-doxology-nat
@@ -0,0 +1,7 @@
id: lauds-hymn-advent-doxology-per-annum
text:
la: "Laus, honor, virtus, glória,\nDeo Patri, et Fílio,\nSancto simul Paráclito,\nIn sæculórum sǽcula.\nAmen."
en: "Honour, glory, virtue, merit,\nTo the Father and the Son,\nWith the co-eternal Spirit,\nWhile eternal ages run.\nAmen."
status:
la: draft
en: draft
@@ -29,12 +29,6 @@ text:
Mundúmque horror cínxerit,
Non pro reátu púniat,
Sed nos pius tunc prótegat.
Laus, honor, virtus, glória,
Deo Patri, et Fílio,
Sancto simul Paráclito,
In sæculórum sǽcula.
Amen.
en: |
Hark, a herald voice is calling;
"Christ is nigh," it seems to say;
@@ -55,12 +49,6 @@ text:
Wrapping all the earth in fear,
May he then as our defender
On the clouds of heaven appear.
Honour, glory, virtue, merit,
To the Father and the Son,
With the co-eternal Spirit,
While eternal ages run.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: lauds-hymn-friday-doxology-per-annum
text:
la: "Deo Patri sit glória,\nEjúsque soli Fílio,\nCum Spíritu Paráclito,\nEt nunc, et in perpétuum.\nAmen."
en: "All laud to God the Father be,\nAll praise, Eternal Son, to thee:\nAll glory, as is ever meet,\nTo God the holy Paraclete,\nAmen."
status:
la: verified
en: verified
@@ -26,12 +26,6 @@ text:
Radícet altis sénsibus:
Secúnda spes congáudeat,
Qua major exstat cáritas.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum.
Amen.
en: |
O Christ, whose glory fills the heaven,
Our only hope, in mercy given;
@@ -57,12 +51,6 @@ text:
With joyous hope, in thee to live;
That lifes rough way may ever be
Made strong and pure by charity.
All laud to God the Father be,
All praise, Eternal Son, to thee:
All glory, as is ever meet,
To God the holy Paraclete,
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: lauds-hymn-lent-doxology-per-annum
text:
la: "Te rerum univérsitas,\nClemens, adóret, Trínitas,\nEt nos novi per véniam,\nNovum canámus cánticum.\nAmen."
en: "May heaven and earth aloud proclaim\nThe Trinity's almighty fame;\nAnd we, restored to grace, rejoice\nIn newness both of heart and voice.\nAmen."
status:
la: draft
en: draft
@@ -25,12 +25,6 @@ text:
In qua reflórent ómnia:
Lætémur in hac ad tuam
Per hanc redúcti grátiam.
Te rerum univérsitas,
Clemens, adóret, Trínitas,
Et nos novi per véniam,
Novum canámus cánticum.
Amen.
en: |
Jesu, salvation's Sun Divine,
Within our inmost bosoms shine,
@@ -51,12 +45,6 @@ text:
The days of joy for them that mourn;
May we of their indulgence share,
And bless the God that grants our prayer.
May heaven and earth aloud proclaim
The Trinity's almighty fame;
And we, restored to grace, rejoice
In newness both of heart and voice.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: lauds-hymn-monday-doxology-per-annum
text:
la: "Deo Patri sit glória,\nEjúsque soli Fílio,\nCum Spíritu Paráclito,\nEt nunc et in perpétuum.\nAmen."
en: "All laud to God the Father be;\nAll praise, Eternal Son, to thee;\nAll glory, as is ever meet,\nTo God the Holy Paraclete.\nAmen."
status:
la: verified
en: verified
@@ -41,12 +41,6 @@ text:
Auróra totus pródeat,
In Patre totus Fílius,
Et totus in Verbo Pater.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc et in perpétuum.
Amen.
en: |
O splendour of Gods glory bright,
O thou that bringest light from light,
@@ -87,12 +81,6 @@ text:
Let him come forth our perfect morn,
The Word in God the Father One,
The Father perfect in the Son.
All laud to God the Father be;
All praise, Eternal Son, to thee;
All glory, as is ever meet,
To God the Holy Paraclete.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: lauds-hymn-paschaltide-doxology-per-annum
text:
la: "Glória tibi Dómine,\nQui surrexísti a mórtuis,\nCum Patre et Sancto Spíritu,\nIn sempitérna sǽcula.\nAmen."
en: "To God the Father let us sing,\nTo God the Son, our risen King,\nAnd equally let us adore\nThe Spirit, God forevermore.\nAmen."
status:
la: draft
en: draft
@@ -30,12 +30,6 @@ text:
In hoc pascháli gáudio,
Ab omni mortis ímpetu
Tuum defénde pópulum.
Glória tibi Dómine,
Qui surrexísti a mórtuis,
Cum Patre et Sancto Spíritu,
In sempitérna sǽcula.
Amen.
en: |
The morn had spread her crimson rays,
When rang the skies with shouts of praise;
@@ -61,12 +55,6 @@ text:
When at the font his name we chose;
Oh, let not sin our robes defile,
And turn to grief the paschal smile.
To God the Father let us sing,
To God the Son, our risen King,
And equally let us adore
The Spirit, God forevermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: lauds-hymn-passiontide-doxology-per-annum
text:
la: "Glória et honor Deo\nUsquequáque altíssimo:\nUna Patri, Filióque,\nInclyto Paráclito:\nCui laus est et potéstas\nPer ætérna sǽcula.\nAmen."
en: "To the Trinity be glory\nEverlasting, as is meet;\nEqual to the Father, equal\nTo the Son, and Paraclete:\nTrinal Unity, whose praises\nAll created things repeat.\nAmen."
status:
la: draft
en: draft
@@ -40,14 +40,6 @@ text:
Nauta mundo náufrago,
Quem sacer cruor perúnxit,
Fusus Agni córpore.
Glória et honor Deo
Usquequáque altíssimo:
Una Patri, Filióque,
Inclyto Paráclito:
Cui laus est et potéstas
Per ætérna sǽcula.
Amen.
en: |
Thirty years among us dwelling,
His appointed time fulfilled,
@@ -83,14 +75,6 @@ text:
Harbour, like the ark of old;
With the sacred blood anointed
From the smitten Lamb that rolled.
To the Trinity be glory
Everlasting, as is meet;
Equal to the Father, equal
To the Son, and Paraclete:
Trinal Unity, whose praises
All created things repeat.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: lauds-hymn-saturday-doxology-per-annum
text:
la: "Glória tibi Dómine,\nQui natus es de Vírgine,\nCum Patre et Sancto Spíritu,\nIn sempitérna sǽcula.\nAmen."
en: "All honour, laud, and glory be,\nO Jesu, Virgin-born, to thee;\nAll glory, as is ever meet,\nTo Father and to Paraclete.\nAmen."
status:
la: verified
en: verified
@@ -20,12 +20,6 @@ text:
Et porta lucis fúlgida:
Vitam datam per Vírginem,
Gentes redémptæ, pláudite.
Glória tibi Dómine,
Qui natus es de Vírgine,
Cum Patre et Sancto Spíritu,
In sempitérna sǽcula.
Amen.
en: |
O glorious lady! throned on high
Above the star-illumined sky;
@@ -41,12 +35,6 @@ text:
Light's gateway fair and glistering;
Life through a Virgin is restored;
Ye ransomed nations, praise the Lord!
All honour, laud, and glory be,
O Jesu, Virgin-born, to thee;
All glory, as is ever meet,
To Father and to Paraclete.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: lauds-hymn-sunday-doxology-per-annum
text:
la: "Præstet hoc nobis Déitas beáta\nPatris, ac Nati, paritérque Sancti\nSpíritus, cujus réboat in omni\nGlória mundo.\nAmen."
en: "This be our portion, God forever blessed,\nFather eternal, Son, and Holy Spirit,\nWhose is the glory, which through all creation\nEver resoundeth.\nAmen."
status:
la: verified
en: verified
@@ -11,12 +11,6 @@ text:
Pellat languórem, tríbuat salútem,
Donet et nobis pietáte Patris
Regna polorum.
Præstet hoc nobis Déitas beáta
Patris, ac Nati, paritérque Sancti
Spíritus, cujus réboat in omni
Glória mundo.
Amen.
en: |
Lo, the dim shadows of the night are waning;
Lightsome and blushing, dawn of day returneth;
@@ -27,12 +21,6 @@ text:
Banish all troubles, kindly health bestowing;
And may he grant us, of his countless blessings,
Peace that is endless.
This be our portion, God forever blessed,
Father eternal, Son, and Holy Spirit,
Whose is the glory, which through all creation
Ever resoundeth.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: lauds-hymn-thursday-doxology-per-annum
text:
la: "Deo Patri sit glória,\nEjúsque soli Fílio,\nCum Spíritu Paráclito,\nEt nunc, et in perpétuum.\nAmen."
en: "Unto God the Father, Son,\nHoly Spirit, Three in One,\nOne in Three, be glory done,\nNow and evermore.\nAmen."
status:
la: verified
en: verified
@@ -21,12 +21,6 @@ text:
Qui nos diébus ómnibus,
Actúsque nostros próspicit
A luce prima in vésperum.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum.
Amen.
en: |
See the golden sun arise!
Let no more our darkened eyes
@@ -47,12 +41,6 @@ text:
All we do, and think, and say,
Watching us from break of day
Till the twilight fall.
Unto God the Father, Son,
Holy Spirit, Three in One,
One in Three, be glory done,
Now and evermore.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: lauds-hymn-tuesday-doxology-per-annum
text:
la: "Deo Patri sit glória,\nEjúsque soli Fílio,\nCum Spíritu Paráclito,\nEt nunc, et in perpétuum.\nAmen."
en: "Unto God the Father, Son,\nHoly Spirit, Three in One,\nOne in Three, be glory done,\nNow and evermore.\nAmen."
status:
la: verified
en: verified
@@ -21,12 +21,6 @@ text:
Tu rumpe noctis víncula:
Tu solve peccátum vetus,
Novúmque lumen íngere.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum.
Amen.
en: |
As the bird, whose clarion gay
Sounds before the dawn is grey,
@@ -47,12 +41,6 @@ text:
Forged by Adams ancient crime;
And the light of Edens prime
To the world restore!
Unto God the Father, Son,
Holy Spirit, Three in One,
One in Three, be glory done,
Now and evermore.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: lauds-hymn-wednesday-doxology-per-annum
text:
la: "Deo Patri sit glória,\nEjúsque soli Fílio,\nCum Spíritu Paráclito,\nEt nunc, et in perpétuum.\nAmen."
en: "Unto God the Father, Son,\nHoly Spirit, Three in One,\nOne in Three, be glory done,\nNow and evermore.\nAmen."
status:
la: verified
en: verified
@@ -21,12 +21,6 @@ text:
Quæ luce purgéntur tua:
Tu, lux Eói síderis,
Vultu seréno illúmina.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum.
Amen.
en: |
Day is breaking, dawn is bright:
Hence, vain shadows of the night!
@@ -47,12 +41,6 @@ text:
All that leads our thoughts astray!
Through our spirits, King of day,
Pour thy light divine!
Unto God the Father, Son,
Holy Spirit, Three in One,
One in Three, be glory done,
Now and evermore.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,16 @@
# The ferial Matins hymn's own natural doxology ending, split out of
# matins-hymn-ferial.yml so hours/matins.ts can swap it seasonally via
# hymn-doxology.ts — the reference source's weekday (Day1-6) Matins hymns
# each carry a real "*" substitution marker here, live-checked in
# Psalterium/Special/Matutinum Special.txt, all sharing this same Latin
# ending; the Sunday (Day0) form has no such marker (its own doxology,
# "Præstet hoc nobis Déitas beáta...", is fixed) — not modeled here since
# vu's Matins doesn't distinguish Sunday from ferial (see matins.ts).
# Text/status carried over unchanged from the original file.
id: matins-hymn-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum. Amen."
en: "Grant this, O Father ever One\nWith Christ, thy sole-begotten Son,\nAnd Holy Ghost, whom all adore,\nReigning and blest forevermore. Amen."
status:
la: verified
en: verified
+5 -18
View File
@@ -4,6 +4,11 @@
# year-round text; only this one (evidently the ordinary-time/per-annum
# form) is authored so far. Seasonal variants deferred (see TODO.md),
# same incremental-content pattern as everywhere else in this project.
#
# The closing doxology stanza is split out into
# matins-hymn-doxology-per-annum.yml (see hours/matins.ts) — the source
# carries a real "*" seasonal-substitution marker there (live-checked
# 2026-09-03, Psalterium/Special/Matutinum Special.txt).
id: matins-hymn-ferial
text:
la: >-
@@ -41,15 +46,6 @@ text:
Et ore te canéntium
Laudéris in perpétuum.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum. Amen.
en: >-
Our limbs refreshed with slumber now,
@@ -85,15 +81,6 @@ text:
That by their lips who thee adore
Thou mayst be praised forevermore.
Grant this, O Father ever One
With Christ, thy sole-begotten Son,
And Holy Ghost, whom all adore,
Reigning and blest forevermore. Amen.
status:
la: verified
en: verified
@@ -0,0 +1,7 @@
id: vespers-hymn-advent-doxology-per-annum
text:
la: "Laus, honor, virtus, glória,\nDeo Patri, et Fílio,\nSancto simul Paráclito,\nIn sæculórum sǽcula.\nAmen."
en: "Be glory given and honour done\nTo God the Father and the Son\nAnd to the Holy Ghost on high,\nFrom age to age eternally.\nAmen."
status:
la: draft
en: draft
@@ -36,12 +36,6 @@ text:
Ventúre judex sǽculi,
Consérva nos in témpore
Hostis a telo pérfidi.
Laus, honor, virtus, glória,
Deo Patri, et Fílio,
Sancto simul Paráclito,
In sæculórum sǽcula.
Amen.
en: |
Bright builder of the heavenly poles,
Eternal light of faithful souls,
@@ -67,12 +61,6 @@ text:
Shalt be our Judge, we humbly pray
Such arms of heavenly grace to send
As may thy Church from foes defend.
Be glory given and honour done
To God the Father and the Son
And to the Holy Ghost on high,
From age to age eternally.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-friday-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum.\nAmen."
en: "Grant this, O Father, ever One\nWith Christ, thy sole-begotten Son,\nWhom, with the Spirit we adore,\nOne God, both now and evermore.\nAmen."
status:
la: draft
en: draft
@@ -26,12 +26,6 @@ text:
Da gratiárum múnera:
Dissólve litis víncula:
Astrínge pacis fœ́dera.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
Maker of man, who from thy throne
Dost order all things, God alone;
@@ -52,12 +46,6 @@ text:
And grant thy gifts of grace below;
From chains of strife our souls release,
Bind fast the gentle bands of peace.
Grant this, O Father, ever One
With Christ, thy sole-begotten Son,
Whom, with the Spirit we adore,
One God, both now and evermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-lent-doxology-per-annum
text:
la: "Præsta, beáta Trínitas,\nConcéde, simplex Únitas;\nUt fructuósa sint tuis\nJejuniórum múnera.\nAmen."
en: "We pray thee, Holy Trinity,\nOne God, unchanging Unity,\nThat we from this our abstinence\nMay reap the fruits of penitence.\nAmen."
status:
la: draft
en: draft
@@ -26,12 +26,6 @@ text:
Dona per abstinéntiam,
Jejúnet ut mens sóbria
A labe prorsus críminum.
Præsta, beáta Trínitas,
Concéde, simplex Únitas;
Ut fructuósa sint tuis
Jejuniórum múnera.
Amen.
en: |
O kind Creator, bow thine ear
To mark the cry, to know the tear
@@ -52,12 +46,6 @@ text:
From discipline of outward things,
That fasting inward secretly
The soul may purely dwell with thee.
We pray thee, Holy Trinity,
One God, unchanging Unity,
That we from this our abstinence
May reap the fruits of penitence.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-monday-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum.\nAmen."
en: "Grant this, O Father, ever One\nWith Christ, thy sole-begotten Son,\nAnd Holy Ghost, whom all adore,\nReigning and blest forevermore.\nAmen."
status:
la: draft
en: draft
@@ -25,12 +25,6 @@ text:
Sic lúminis jubar ferat:
Ut vana cuncta próterat:
Hanc falsa nulla cómprimant.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O great Creator of the sky,
Who wouldest not the floods on high
@@ -51,12 +45,6 @@ text:
So shall its rays direct us right:
And let this faith each error chase,
And never give to falsehood place.
Grant this, O Father, ever One
With Christ, thy sole-begotten Son,
And Holy Ghost, whom all adore,
Reigning and blest forevermore.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-paschaltide-doxology-per-annum
text:
la: "Glória tibi Dómine,\nQui surrexísti a mórtuis,\nCum Patre et Sancto Spíritu,\nIn sempitérna sǽcula.\nAmen."
en: "Hymns of glory, songs of praise,\nFather, unto thee we raise;\nRisen Lord, all praise to thee,\nEver with the Spirit be.\nAmen."
status:
la: draft
en: draft
@@ -44,12 +44,6 @@ text:
In hoc pascháli gáudio,
Ab omni mortis ímpetu
Tuum defénde pópulum.
Glória tibi Dómine,
Qui surrexísti a mórtuis,
Cum Patre et Sancto Spíritu,
In sempitérna sǽcula.
Amen.
en: |
At the Lamb's high feast we sing
Praise to our victorious King,
@@ -85,12 +79,6 @@ text:
Only sin can this destroy;
From the death of sin set free,
Souls re-born, dear Lord, in Thee.
Hymns of glory, songs of praise,
Father, unto thee we raise;
Risen Lord, all praise to thee,
Ever with the Spirit be.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-passiontide-doxology-per-annum
text:
la: "Te summa, Deus, Trínitas,\nColláudet omnis spíritus:\nQuos per Crucis mystérium\nSalvas, rege per sǽcula.\nAmen."
en: "Blest Trinity, salvation's spring,\nMay every soul thy praises sing;\nTo those thou grantest conquest by\nThe holy cross, rewards apply.\nAmen."
status:
la: draft
en: draft
@@ -45,12 +45,6 @@ text:
Hoc Passiónis témpore
Auge piis justítiam,
Reísque dona véniam.
Te summa, Deus, Trínitas,
Colláudet omnis spíritus:
Quos per Crucis mystérium
Salvas, rege per sǽcula.
Amen.
en: |
Abroad the regal banners fly,
Now shines the cross's mystery;
@@ -82,12 +76,6 @@ text:
This holy Passiontide,
To give fresh merit to the saint,
And pardon to the penitent.
Blest Trinity, salvation's spring,
May every soul thy praises sing;
To those thou grantest conquest by
The holy cross, rewards apply.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-saturday-doxology-per-annum
text:
la: "Deo Patri sit glória,\nEjúsque soli Fílio,\nCum Spíritu Paráclito,\nEt nunc, et in perpétuum.\nAmen."
en: "All laud to God the Father be;\nall praise, Eternal Son, to Thee;\nall glory, as is ever meet,\nto God the Holy Paraclete.\nAmen."
status:
la: draft
en: draft
@@ -16,12 +16,6 @@ text:
Te deprecémur véspere:
Te nostra supplex glória
Per cuncta laudet sǽcula.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum.
Amen.
en: |
O Trinity of blessed Light,
O Unity of sovereign might,
@@ -32,12 +26,6 @@ text:
to Thee our evening prayer we raise;
Thee may our glory evermore
in lowly reverence adore.
All laud to God the Father be;
all praise, Eternal Son, to Thee;
all glory, as is ever meet,
to God the Holy Paraclete.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,17 @@
# Sunday Vespers' own natural doxology ending ("Lucis Creator", split out
# of vespers-hymn-sunday.yml so hours/vespers.ts can swap it seasonally via
# hymn-doxology.ts — the reference source carries a real "*" substitution
# marker here, live-checked in Psalterium/Special/Major Special.txt's
# "[Hymnus Day0 Vespera]", which the Monastic "[HymnusM Day0 Vespera]"
# inherits unchanged (its own two `s///` substitutions don't touch the
# doxology line) — unlike the weekday (Day1-6) and Paschaltide Vespers
# hymns, whose Monastic forms are each a separate, fixed, non-swapping
# text with no such marker. Text/status carried over unchanged from the
# original file.
id: vespers-hymn-sunday-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum.\nAmen."
en: "O Father, that we ask be done,\nThrough Jesus Christ, thine only Son;\nWho, with the Holy Ghost and thee,\nDoth live and reign eternally.\nAmen."
status:
la: draft
en: draft
@@ -6,6 +6,11 @@
# here rather than left as a diff — not live-query-verified (see TODO.md).
# English has no separate Monastic variant in the source (the wording
# differences don't affect translation), so it's the same text either way.
# The closing doxology stanza is split out into
# vespers-hymn-sunday-doxology-per-annum.yml (see hours/vespers.ts) — the source
# carries a real "*" seasonal-substitution marker there (live-checked
# 2026-09-03, Psalterium/Special/Major Special.txt), unlike every other
# Lauds/Vespers weekday hymn's fixed ending.
id: vespers-hymn-sunday
text:
la: |
@@ -28,12 +33,6 @@ text:
Vitále tollat prǽmium:
Vitémus omne nóxium:
Purgémus omne péssimum.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O blest Creator of the light,
Who mak'st the day with radiance bright,
@@ -54,12 +53,6 @@ text:
The heavenly gate and prize to gain:
Each harmful lure aside to cast,
And purge away each error past.
O Father, that we ask be done,
Through Jesus Christ, thine only Son;
Who, with the Holy Ghost and thee,
Doth live and reign eternally.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-thursday-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum.\nAmen."
en: "This boon, O Father, we entreat,\nThis blessing grant, Eternal Son,\nAnd Holy Ghost, the Paraclete,\nBoth now, and while the ages run.\nAmen."
status:
la: draft
en: draft
@@ -27,12 +27,6 @@ text:
Nullum levet jactántia:
Elísa mens ne cóncidat:
Eláta mens ne córruat.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O sovereign Lord of nature's might,
Who bad'st the water's birth divide;
@@ -53,12 +47,6 @@ text:
The humble cheer, the high control;
Check in each heart its proud excess,
But raise the meek and contrite soul!
This boon, O Father, we entreat,
This blessing grant, Eternal Son,
And Holy Ghost, the Paraclete,
Both now, and while the ages run.
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-tuesday-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum.\nAmen."
en: "Hear thou our prayer, Almighty King!\nHear thou our praises, while we sing,\nAdoring with the heavenly host,\nThe Father, Son, and Holy Ghost!\nAmen."
status:
la: draft
en: draft
@@ -27,12 +27,6 @@ text:
Nullis malis appróximet:
Bonis repléri gáudeat,
Et mortis actum nésciat.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
Earth's mighty Maker, whose command
Raised from the sea the solid land;
@@ -53,12 +47,6 @@ text:
And keep from every evil way;
Rejoice each promised good to win,
And flee from every mortal sin.
Hear thou our prayer, Almighty King!
Hear thou our praises, while we sing,
Adoring with the heavenly host,
The Father, Son, and Holy Ghost!
Amen.
status:
la: draft
en: draft
@@ -0,0 +1,7 @@
id: vespers-hymn-wednesday-doxology-per-annum
text:
la: "Præsta, Pater piíssime,\nPatríque compar Únice,\nCum Spíritu Paráclito\nRegnans per omne sǽculum.\nAmen."
en: "Grant this, O Father, ever One\nWith Christ thy sole-begotten Son,\nWhom, with the Spirit we adore,\nOne God, both now and evermore.\nAmen."
status:
la: draft
en: draft
@@ -27,12 +27,6 @@ text:
Abstérge sordes méntium:
Resólve culpæ vínculum:
Evérte moles críminum.
Præsta, Pater piíssime,
Patríque compar Únice,
Cum Spíritu Paráclito
Regnans per omne sǽculum.
Amen.
en: |
O God, whose hand hath spread the sky,
And all its shining hosts on high,
@@ -53,12 +47,6 @@ text:
Polluted souls make pure again:
Unloose the bands of guilt within:
Remove the burden of our sin.
Grant this, O Father, ever One
With Christ thy sole-begotten Son,
Whom, with the Spirit we adore,
One God, both now and evermore.
Amen.
status:
la: draft
en: draft
+1 -3
View File
@@ -30,9 +30,7 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
return [{ kind: 'hymn', text: resolveCommon('compline-hymn-lenten') }];
}
const body = resolveCommon(part.textRef.id);
const doxology = resolveCommon(
getHymnDoxologyId(day.season, day.winner, 'compline-hymn-doxology-per-annum'),
);
const doxology = resolveCommon(getHymnDoxologyId(day, 'compline-hymn-doxology-per-annum'));
return [{ kind: 'hymn', text: appendDoxology(body, doxology) }];
}
case 'chapter':
+42 -8
View File
@@ -1,21 +1,55 @@
import type { Season, DayWinner } from '../calendar/types';
import { resolveSeasonalPropersId } from './seasonal-propers';
import type { LiturgicalDay } from '../calendar/types';
import { resolveOfficeWinner } from './resolve-common';
import bySeasonData from '../data/hours/hymn-doxology-by-season.yml';
import byFeastData from '../data/hours/hymn-doxology-by-feast.yml';
const bySeason = bySeasonData as { bySeason: Record<string, string> };
const byFeast = byFeastData as { byFeastId: Record<string, string> };
const NAT_DOXOLOGY_ID = 'hymn-doxology-nat';
/**
* Divinum Officium's own doxology() sub (specials/hymni.pl) hardcodes the
* Assumption's octave (Aug 16-22) to the Nativity doxology, regardless of
* season or which feast is winning that day — live-checked in the source,
* and *not* excluded for the Monastic/Tridentine 1617 track (unlike its
* Dec 9-15 companion rule for the Immaculate Conception's run-up, which the
* source explicitly excludes 1570/1617/1963/altovadensis from, so that one
* is deliberately NOT ported here). Checked directly by date, same pattern
* as marian-antiphon.ts's isCandlemasToHolyWednesday — this window doesn't
* line up with any `Season` value.
*/
function isAssumptionOctaveWindow(isoDate: string): boolean {
const [, monthStr, dayStr] = isoDate.split('-');
const month = Number(monthStr);
const day = Number(dayStr);
return month === 8 && day > 15 && day < 23;
}
/**
* Resolves the common-propers id for a hymn's seasonal final doxology
* stanza. The seasonal overrides are shared across every hymn (Divinum
* Officium's own Doxologies.txt table is hymn-agnostic), but the per-annum
* default is each hymn's own natural ending, so callers supply it.
*
* Precedence, matching hymni.pl's doxology() sub: (1) an explicit per-feast
* override — real Divinum Officium's `winner{Doxology}`/`Rule Doxology=`
* mechanism, e.g. the Common of the BVM's own `Doxology=Nat` rule, which is
* why Marian Saturdays (a `kind: 'temporal'` winner, not `'sanctoral'` —
* checked regardless of kind, unlike chapter-responsory's/opening-
* versicle's own byFeastId tables, since a temporal id and a sanctoral id
* never collide) get the Nativity doxology even outside Christmastide; (2)
* the Assumption-octave date window above; (3) the season; (4) the hymn's
* own per-annum default.
*/
export function getHymnDoxologyId(season: Season, winner: DayWinner, perAnnumId: string): string {
return resolveSeasonalPropersId(season, winner, {
perAnnum: perAnnumId,
bySeason: bySeason.bySeason,
byFeastId: byFeast.byFeastId,
});
export function getHymnDoxologyId(day: LiturgicalDay, perAnnumId: string): string {
const winner = resolveOfficeWinner(day);
const feastOverride = winner.kind === 'sanctoral' || winner.kind === 'temporal' ? byFeast.byFeastId[winner.id] : undefined;
if (feastOverride) {
return feastOverride;
}
if (isAssumptionOctaveWindow(day.date)) {
return NAT_DOXOLOGY_ID;
}
return bySeason.bySeason[day.season] ?? perAnnumId;
}
+27 -1
View File
@@ -6,10 +6,12 @@ import { getPsalmVerses } from '../psalter';
import { getCanticle, type CanticleVerse } from './lauds-canticles';
import { getLaudsSaintOverride, getLaudsCommonOverride, type LaudsPsalmodyOverride } from './lauds-psalmody-overrides';
import { getOpeningVersicleId } from './opening-versicle';
import { getHymnDoxologyId } from './hymn-doxology';
import { getMarianAntiphonId, getMarianAntiphonLabel } from './marian-antiphon';
import { applyFlexaMark } from './antiphon';
import {
resolveCommon,
appendDoxology,
getDayCollects,
getBenedictusAntiphon,
splitNamedAntiphon,
@@ -261,6 +263,30 @@ function resolvePsalmody(day: LiturgicalDay): ResolvedPart[] {
return parts;
}
/**
* Every plain-default Lauds hymn's own closing doxology stanza (split out
* into `lauds-hymn-${key}-doxology-per-annum.yml`) is re-attached here
* through the seasonal mechanism (hours/hymn-doxology.ts) rather than kept
* as fixed text — a deliberate broadening beyond the reference source
* (whose Monastic weekday/seasonal Lauds hymns mostly don't vary their own
* doxology by season at all, live-checked 2026-09-03): this project isn't
* a reconstruction (see the repo's CLAUDE.md), and a hymn's closing
* doxology is a natural, low-cost way to keep every hour visibly in step
* with the season — e.g. the plain weekday hymns used all through
* Christmastide/Epiphanytide/Corpus Christi/Sacred Heart (no
* `seasonalOfficeSuffix` covers those) previously stayed on their generic
* per-annum ending throughout; now they pick up Nat/Epi/Corp/Heart like
* Prime/Compline already did. Each `key`'s own natural ending is preserved
* as that key's per-annum default, so a season/feast with no override
* (e.g. Advent, Lent — the source itself never swaps those) reproduces the
* exact original text.
*/
function resolveLaudsHymn(day: LiturgicalDay, key: string): ResolvedText {
const body = resolveCommon(`lauds-hymn-${key}`);
const doxology = resolveCommon(getHymnDoxologyId(day, `lauds-hymn-${key}-doxology-per-annum`));
return appendDoxology(body, doxology);
}
/** Any sanctoral winner's (or named-temporal feast's) own capitulum/
* responsory/hymn/versicle (data/propers/common/lauds-{part}-${id}.yml),
* else their Common's (`${part}-${common}`), when authored — see
@@ -287,7 +313,7 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
return [
{ kind: 'chapter', text: resolveCommon(seasonSuffix ? `lauds-capitulum-${key}` : capitulumId(day.weekday)) },
{ kind: 'responsory', text: resolveResponsory(resolveCommon(`lauds-responsory-${key}`), day) },
{ kind: 'hymn', text: resolveCommon(`lauds-hymn-${key}`) },
{ kind: 'hymn', text: resolveLaudsHymn(day, key) },
{ kind: 'versicle', text: resolveCommon(`lauds-versicle-${key}`) },
];
}
+10 -1
View File
@@ -76,9 +76,11 @@ import { getPsalmVerses } from '../psalter';
import { getPsalmsFor, type PsalmRef } from '../psalter/distribution';
import { getScriptureVerses } from '../scripture';
import { getOpeningVersicleId } from './opening-versicle';
import { getHymnDoxologyId } from './hymn-doxology';
import { applyFlexaMark } from './antiphon';
import {
resolveCommon,
appendDoxology,
getDayCollect,
getOfficeOverrideId,
resolveOfficeWinner,
@@ -454,7 +456,14 @@ function resolveMatinsHymn(day: LiturgicalDay): ResolvedText {
return seasonal;
}
}
return resolveCommon('matins-hymn-ferial');
// The plain ferial hymn's own Monastic source (Day1-6 Hymnus, Psalterium/
// Special/Matutinum Special.txt) carries a real seasonal-doxology
// substitution marker (live-checked 2026-09-03) — unlike the Advent/
// Paschaltide seasonal hymns above, whose Monastic forms are each fixed,
// non-swapping text, so only this final fallback needs the swap.
const body = resolveCommon('matins-hymn-ferial');
const doxology = resolveCommon(getHymnDoxologyId(day, 'matins-hymn-doxology-per-annum'));
return appendDoxology(body, doxology);
}
/** The plain ferial weekday nocturn's real antiphoned psalmody — a
+1 -1
View File
@@ -30,7 +30,7 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
switch (part.kind) {
case 'hymn': {
const body = resolveCommon(part.textRef.id);
const doxology = resolveCommon(getHymnDoxologyId(day.season, day.winner, 'hymn-doxology-per-annum'));
const doxology = resolveCommon(getHymnDoxologyId(day, 'hymn-doxology-per-annum'));
return [{ kind: 'hymn', text: appendDoxology(body, doxology) }];
}
case 'chapter':
+26 -1
View File
@@ -5,10 +5,12 @@ import { weekdayOf } from '../calendar/weekday';
import { getDayLabel } from '../calendar/day-label';
import { getPsalmVerses } from '../psalter';
import { getOpeningVersicleId } from './opening-versicle';
import { getHymnDoxologyId } from './hymn-doxology';
import { getVespersSaintOverride, getVespersCommonOverride } from './vespers-psalmody-overrides';
import { applyFlexaMark } from './antiphon';
import {
resolveCommon,
appendDoxology,
getDayCollects,
getMagnificatAntiphon,
splitNamedAntiphon,
@@ -170,6 +172,29 @@ function vespersCapitulumForOverride(id: string): ResolvedText {
return resolveCommon(`lauds-capitulum-${id}`);
}
/**
* Every plain-default Vespers hymn's own closing doxology stanza (split
* out into `vespers-hymn-${key}-doxology-per-annum.yml`) is re-attached
* here through the seasonal mechanism (hours/hymn-doxology.ts) — Sunday's
* hymn ("Lucis Creator") is the one case in Lauds/Vespers/Matins' whole
* weekday-default set whose Monastic source text carries a real "*"
* seasonal-substitution marker (live-checked 2026-09-03), but every other
* key is wired the same way anyway as a deliberate broadening beyond the
* source: this project isn't a reconstruction (see the repo's CLAUDE.md),
* and the doxology is a natural, low-cost way to keep every hour visibly
* in step with the season — e.g. the plain weekday hymns used all through
* Christmastide/Epiphanytide/Corpus Christi/Sacred Heart (no
* `seasonalOfficeSuffix` covers those) previously stayed on their generic
* per-annum ending throughout. Each key's own natural ending is preserved
* as its per-annum default, so a season/feast with no override (e.g.
* Advent, Lent — the source itself never swaps those) reproduces the
* exact original text. See lauds.ts's identical resolveLaudsHymn. */
function resolveVespersHymn(day: LiturgicalDay, key: string): ResolvedText {
const body = resolveCommon(`vespers-hymn-${key}`);
const doxology = resolveCommon(getHymnDoxologyId(day, `vespers-hymn-${key}-doxology-per-annum`));
return appendDoxology(body, doxology);
}
/** The chapter/responsory/hymn/versicle bundle following the psalmody —
* see hours/types.ts's 'vespers-office' doc comment. Any sanctoral
* winner's (or named-temporal feast's) own proper bundle (chapter via
@@ -207,7 +232,7 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
kind: 'responsory',
text: resolveResponsory(resolveCommon(seasonSuffix ? `vespers-responsory-${key}` : vespersResponsoryId(day.weekday)), day),
},
{ kind: 'hymn', text: resolveCommon(`vespers-hymn-${key}`) },
{ kind: 'hymn', text: resolveVespersHymn(day, key) },
{
kind: 'versicle',
text: resolveCommon(seasonSuffix ? `vespers-versicle-${key}` : vespersVersicleId(day.weekday)),