Compare commits
2 Commits
2d957ae111
...
750ccbf6d4
| Author | SHA1 | Date | |
|---|---|---|---|
| 750ccbf6d4 | |||
| 9571a807de |
@@ -2768,6 +2768,50 @@ unauthored — 2029-01-17, confirmed clean). `npm test` (471 tests), `tsc --noEm
|
|||||||
Virgin-Martyr [17], Abbot [16], Holy Woman [3], Widow [6], Angel [5], Evangelist [3], and the
|
Virgin-Martyr [17], Abbot [16], Holy Woman [3], Widow [6], Angel [5], Evangelist [3], and the
|
||||||
smaller one-off Commons — none has a category file yet.
|
smaller one-off Commons — none has a category file yet.
|
||||||
|
|
||||||
|
### Lauds/Vespers chapter-responsory-hymn-versicle bundle: rank-agnostic Common fallback (2026-08-25)
|
||||||
|
|
||||||
|
**Bug fixed**: St. Louis (2026-08-25, `common-of-a-confessor-not-bishop`, Simplex, wins
|
||||||
|
outright) was showing the plain ferial chapter/hymn at Lauds instead of his own Common's —
|
||||||
|
`hours/lauds.ts`'s `resolveOffice` only substituted a feast's own proper bundle
|
||||||
|
(`lauds-{part}-<id>.yml`), gated at duplex-majus+ (piggybacking eligibility on the Lauds
|
||||||
|
psalmody-override table, itself majus+-only by design), with no Common-level fallback at all.
|
||||||
|
Same gap existed in `hours/vespers.ts`'s identical `resolveOffice`. Fixed by adding
|
||||||
|
`resolve-common.ts`'s `resolveOfficeBundle`: tries the winner's own proper bundle first, then
|
||||||
|
falls back to their Common's bundle (`SaintRecord.common`, the same id driving the day
|
||||||
|
collect — not `minorHoursCommon`, a deliberately different id for P/T/S/N), eligibility tested
|
||||||
|
rank-agnostically via the existing `getMinorHourOverrideId` (any sanctoral winner, not just
|
||||||
|
duplex-majus+) — a simplex feast's own or Common's chapter/hymn is real, distinct liturgical
|
||||||
|
content, not something only strong feasts are entitled to. Vespers' own chapter lookup
|
||||||
|
(`vespersCapitulumForOverride`, which already falls back to the byte-identical Lauds capitulum
|
||||||
|
file when no separate Vespers one exists) is passed in and reused unchanged for both the
|
||||||
|
proper and the Common id.
|
||||||
|
|
||||||
|
**Proof authored**: `common-of-a-confessor-not-bishop`'s full Lauds bundle (chapter, short
|
||||||
|
responsory, hymn "Jesu coróna célsior", versicle) and Vespers bundle (chapter reused from
|
||||||
|
Lauds, short responsory, hymn "Iste Conféssor Dómini sacrátus" — Latin/English text reused
|
||||||
|
verbatim from the already-authored Matins hymn file, same Monastic-track recension — versicle),
|
||||||
|
live-verified against Divinum Officium (Monastic Tridentinum 1617). Lauds content cross-checked
|
||||||
|
byte-identical between St. Louis's own day and St. Nicholas of Tolentino's (`propers: null`,
|
||||||
|
clean year), confirming genuine shared Common content. Vespers content, unusually, had to be
|
||||||
|
sourced via the reference engine's `votive=C5` ("Commune Confessoris non Pontificis") view
|
||||||
|
instead of any real saint's own rendered Second Vespers — every one of this Common's 4 real
|
||||||
|
saints (St. Louis, St. Francis, St. Dominic, St. Nicholas of Tolentino) turned out to have
|
||||||
|
their own Second Vespers permanently outranked by a fixed adjacent feast (St. Zephyrinus's
|
||||||
|
First Vespers, SS. Placid and Companions', Our Lady of the Snows', the Nativity-of-the-BVM
|
||||||
|
octave, respectively) — a structural pattern for this category, not a query mistake. Also
|
||||||
|
corrected a wrong lead from earlier in this investigation: `CommuneM/C4a.txt`'s file-inheritance
|
||||||
|
structure (`@CommuneM/C4`) initially looked like it meant Confessor-Not-Bishop reuses
|
||||||
|
Confessor-Bishop's Office bundle wholesale, but the reference engine's own votive-office naming
|
||||||
|
(C4 = "Confessoris Pontificis", C5 = "Confessoris non Pontificis", C4a = "Doctoris Pontificis" —
|
||||||
|
an unrelated category with a superficially similar filename) settles that these are two
|
||||||
|
genuinely separate Common categories with their own distinct hymns ("Jesu Redémptor ómnium" vs
|
||||||
|
"Jesu coróna célsior" at Lauds).
|
||||||
|
|
||||||
|
`npm test` (471 tests), `tsc --noEmit` both pass. **Still open**: the other 10 Common
|
||||||
|
categories in the "still open" list above have no Lauds/Vespers bundle authored yet either —
|
||||||
|
same honest incremental-content gap, now on a mechanism that no longer silently drops to the
|
||||||
|
ferial default for any rank.
|
||||||
|
|
||||||
## Known, deliberate simplifications (not bugs — working as designed)
|
## Known, deliberate simplifications (not bugs — working as designed)
|
||||||
|
|
||||||
- `getDayCollects`: each collect in a multi-collect day renders as its own
|
- `getDayCollects`: each collect in a multi-collect day renders as its own
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
|
||||||
|
# live query -- St. Louis's own day (2026-08-25) and St. Nicholas of
|
||||||
|
# Tolentino's own day (2026-09-10, `propers: null`) cross-checked
|
||||||
|
# byte-identical, confirming this is genuine shared Common content, not
|
||||||
|
# either saint's own proper. Was falling all the way through to the
|
||||||
|
# plain ferial default before this (see resolve-common.ts's
|
||||||
|
# resolveOfficeBundle) -- Lauds' chapter/responsory/hymn/versicle bundle
|
||||||
|
# was previously gated at duplex-majus+ like the psalmody-override table
|
||||||
|
# it piggybacked eligibility on, wrongly excluding every lower-ranked
|
||||||
|
# Common-of-a-Confessor-Not-Bishop saint (e.g. St. Louis, Simplex) from
|
||||||
|
# their own Common's real content.
|
||||||
|
id: lauds-capitulum-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: "Beátus vir, qui invéntus est sine mácula, et qui post aurum non ábiit, nec sperávit in pecúnia et thesáuris. Quis est hic, et laudábimus eum? fecit enim mirabília in vita sua."
|
||||||
|
en: "Blessed is the rich man that is found without blemish: and that hath not gone after gold, nor put his trust in money nor in treasures. Who is he, and we will praise him? for he hath done wonderful things in his life."
|
||||||
|
citation:
|
||||||
|
la: "Sir 31:8-9"
|
||||||
|
en: "Sir 31:8-9"
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
|
||||||
|
# live query -- St. Louis's own day (2026-08-25) and St. Nicholas of
|
||||||
|
# Tolentino's own day (2026-09-10, `propers: null`) cross-checked
|
||||||
|
# byte-identical -- see lauds-capitulum-common-of-a-confessor-not-
|
||||||
|
# bishop.yml's header for the fuller note on this bundle's gap. "Jesu
|
||||||
|
# coróna célsior" -- self-contained, including its own final doxology
|
||||||
|
# stanza; distinct from the Common-of-a-Confessor-Bishop's own Lauds hymn
|
||||||
|
# ("Jesu Redémptor ómnium") -- the reference engine's votive-office
|
||||||
|
# dropdown separates the two categories as C4 ("Confessoris Pontificis")
|
||||||
|
# and C5 ("Confessoris non Pontificis"), each with its own full Office
|
||||||
|
# bundle, not (as CommuneM/C4a.txt's file-inheritance structure might
|
||||||
|
# suggest at a skim) one category layered as a thin override of the
|
||||||
|
# other -- C4a.txt is actually "Doctoris Pontificis", unrelated to this
|
||||||
|
# category despite the superficially similar filename.
|
||||||
|
id: lauds-hymn-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: |
|
||||||
|
Jesu coróna célsior,
|
||||||
|
Et véritas sublímior,
|
||||||
|
Qui confiténti sérvulo
|
||||||
|
Reddis perénne prǽmium:
|
||||||
|
|
||||||
|
Da supplicánti cœ́tui,
|
||||||
|
Obténtu hujus óptimi,
|
||||||
|
Remissiónem críminum
|
||||||
|
Rumpéndo nexum vínculi.
|
||||||
|
|
||||||
|
Anni recúrso témpore,
|
||||||
|
Dies illúxit lúmine,
|
||||||
|
Quo Sanctus hic de córpore
|
||||||
|
Polum migrávit prǽpotens.
|
||||||
|
|
||||||
|
Hic vana terræ gáudia
|
||||||
|
Et luculénta prǽdia,
|
||||||
|
Pollúta sorde députans,
|
||||||
|
Ovans tenet cæléstia.
|
||||||
|
|
||||||
|
Te, Christe Rex piíssime,
|
||||||
|
Hic confiténdo júgiter,
|
||||||
|
Calcávit hostem fórtiter,
|
||||||
|
Supérbum ac satéllitem.
|
||||||
|
|
||||||
|
Virtútum actu et fide,
|
||||||
|
Confessiónis órdine,
|
||||||
|
Jejúna membra déferens,
|
||||||
|
Dapes supérnas óbtinet.
|
||||||
|
|
||||||
|
Proínde te, piíssime,
|
||||||
|
Precámur omnes súpplices,
|
||||||
|
Ut hujus almi grátia
|
||||||
|
Nobis remíttas débita.
|
||||||
|
|
||||||
|
Glória Patri Dómino,
|
||||||
|
Glória Unigénito,
|
||||||
|
Una cum Sancto Spíritu,
|
||||||
|
In sempitérna sǽcula.
|
||||||
|
Amen.
|
||||||
|
en: |
|
||||||
|
Jesu, eternal truth sublime,
|
||||||
|
Through endless years the same!
|
||||||
|
Thou crown of those who through all time
|
||||||
|
Confess thy holy name:
|
||||||
|
|
||||||
|
Thy suppliant people, through the prayer
|
||||||
|
Of thy blest saint, forgive;
|
||||||
|
For his dear sake, thy wrath forbear,
|
||||||
|
And bid our spirits live.
|
||||||
|
|
||||||
|
Again returns the sacred day,
|
||||||
|
With heavenly glory bright,
|
||||||
|
Which saw him go upon his way
|
||||||
|
Into the realms of light.
|
||||||
|
|
||||||
|
All objects of our vain desire,
|
||||||
|
All earthly joys and gains,
|
||||||
|
To him were but as filthy mire;
|
||||||
|
And now with thee he reigns.
|
||||||
|
|
||||||
|
Thee, Jesu, his all-gracious Lord,
|
||||||
|
Confessing to the last,
|
||||||
|
He trod beneath him Satan's fraud,
|
||||||
|
And stood forever fast.
|
||||||
|
|
||||||
|
In holy deeds of faith and love,
|
||||||
|
In fastings and in prayers,
|
||||||
|
His days were spent; and now above
|
||||||
|
Thy heavenly feast he shares.
|
||||||
|
|
||||||
|
Then, for his sake thy wrath lay by,
|
||||||
|
And hear us while we pray;
|
||||||
|
And pardon us, O thou most high,
|
||||||
|
On this his festal day.
|
||||||
|
|
||||||
|
All glory to the Father be;
|
||||||
|
And sole Incarnate Son;
|
||||||
|
Praise, holy Paraclete, to thee;
|
||||||
|
While endless ages run.
|
||||||
|
Amen.
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
|
||||||
|
# live query -- St. Louis's own day (2026-08-25) and St. Nicholas of
|
||||||
|
# Tolentino's own day (2026-09-10, `propers: null`) cross-checked
|
||||||
|
# byte-identical -- see lauds-capitulum-common-of-a-confessor-not-
|
||||||
|
# bishop.yml's header for the fuller note on this bundle's gap.
|
||||||
|
id: lauds-responsory-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: |
|
||||||
|
R.br. Amávit eum Dóminus, * Et ornávit eum.
|
||||||
|
℟. Amávit eum Dóminus, * Et ornávit eum.
|
||||||
|
℣. Stolam glóriæ índuit eum.
|
||||||
|
℟. Et ornávit eum.
|
||||||
|
℣. Glória Patri, et Fílio, * et Spirítui Sancto.
|
||||||
|
℟. Amávit eum Dóminus, * Et ornávit eum.
|
||||||
|
en: |
|
||||||
|
R.br. The Lord loved him, * and beautified him.
|
||||||
|
℟. The Lord loved him, * and beautified him.
|
||||||
|
℣. He clothed him with a robe of glory.
|
||||||
|
℟. And beautified him.
|
||||||
|
℣. Glory be to the Father, and to the Son, * and to the Holy Ghost.
|
||||||
|
℟. The Lord loved him, * and beautified him.
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
|
||||||
|
# live query -- St. Louis's own day (2026-08-25) and St. Nicholas of
|
||||||
|
# Tolentino's own day (2026-09-10, `propers: null`) cross-checked
|
||||||
|
# byte-identical -- see lauds-capitulum-common-of-a-confessor-not-
|
||||||
|
# bishop.yml's header for the fuller note on this bundle's gap.
|
||||||
|
id: lauds-versicle-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: "V. Justum dedúxit Dóminus per vias rectas.\nR. Et osténdit illi regnum Dei."
|
||||||
|
en: "V. The Lord guided the just in right paths.\nR. And showed him the kingdom of God."
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Vespers,
|
||||||
|
# `votive=C5` live query, 2026-08 -- see vespers-responsory-common-of-a-
|
||||||
|
# confessor-not-bishop.yml's header for why the votive-office view was
|
||||||
|
# used instead of a real saint's own (outranked) Second Vespers. Same
|
||||||
|
# "Iste Conféssor Dómini sacrátus" hymn (Monastic-track pre-Urban VIII
|
||||||
|
# text) already authored for this Common's Matins hymn -- see matins-
|
||||||
|
# hymn-common-of-a-confessor-not-bishop.yml's header for the Monastic-
|
||||||
|
# vs-secular textual-variant note -- so its Latin and English (an
|
||||||
|
# original translation, not the reference engine's own, for the same
|
||||||
|
# reason recorded there) are reused verbatim here rather than
|
||||||
|
# re-translated, for consistency across hours.
|
||||||
|
id: vespers-hymn-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: >-
|
||||||
|
Iste Conféssor Dómini sacrátus,
|
||||||
|
|
||||||
|
Festa plebs cujus celébrat per orbem,
|
||||||
|
|
||||||
|
Hódie lætus méruit secréta
|
||||||
|
|
||||||
|
Scándere cæli.
|
||||||
|
|
||||||
|
|
||||||
|
Qui pius, prudens, húmilis, pudícus,
|
||||||
|
|
||||||
|
Sóbrius, castus fuit et quiétus,
|
||||||
|
|
||||||
|
Vita dum præsens vegetávit ejus
|
||||||
|
|
||||||
|
Córporis artus.
|
||||||
|
|
||||||
|
|
||||||
|
Ob sacrum cujus túmulum frequénter
|
||||||
|
|
||||||
|
Membra languéntum modo sanitáti,
|
||||||
|
|
||||||
|
Quólibet morbo fúerint graváta,
|
||||||
|
|
||||||
|
Restituúntur.
|
||||||
|
|
||||||
|
|
||||||
|
Unde nunc noster chorus in honórem
|
||||||
|
|
||||||
|
Ipsius, hymnum canit hunc libénter:
|
||||||
|
|
||||||
|
Ut piis ejus méritis juvémur
|
||||||
|
|
||||||
|
Omne per ævum.
|
||||||
|
|
||||||
|
|
||||||
|
Sit salus illi, decus atque virtus,
|
||||||
|
|
||||||
|
Qui supra cæli résidens cacúmen,
|
||||||
|
|
||||||
|
Tótius mundi máchinam gubérnat
|
||||||
|
|
||||||
|
Trinus et unus. Amen.
|
||||||
|
en: >-
|
||||||
|
This is the Lord's own hallowed confessor,
|
||||||
|
|
||||||
|
Whose feast today the nations round are keeping;
|
||||||
|
|
||||||
|
Joyful, he merited this day to enter
|
||||||
|
|
||||||
|
Heaven's hid glory.
|
||||||
|
|
||||||
|
|
||||||
|
Dutiful, prudent, humble, chaste, he flourished,
|
||||||
|
|
||||||
|
Sober and quiet, pure in all his living,
|
||||||
|
|
||||||
|
While in his body yet the breath of this life
|
||||||
|
|
||||||
|
Quickened his members.
|
||||||
|
|
||||||
|
|
||||||
|
Often at his consecrated tomb, the
|
||||||
|
|
||||||
|
Limbs of those worn by long and grievous sickness,
|
||||||
|
|
||||||
|
Whatsoever ill had laid them low, are
|
||||||
|
|
||||||
|
Wholly restored.
|
||||||
|
|
||||||
|
|
||||||
|
Therefore our choir today, in glad thanksgiving,
|
||||||
|
|
||||||
|
Sings in his honor this our joyful anthem:
|
||||||
|
|
||||||
|
That by his merits, freely won through goodness,
|
||||||
|
|
||||||
|
We may be aided.
|
||||||
|
|
||||||
|
|
||||||
|
Praise be to Him, all honor, might, dominion,
|
||||||
|
|
||||||
|
Who from the height of heaven's throne is reigning,
|
||||||
|
|
||||||
|
Governing all the fabric of creation,
|
||||||
|
|
||||||
|
Three and yet One. Amen.
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: draft
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Vespers,
|
||||||
|
# `votive=C5` ("Commune Confessoris non Pontificis") live query, 2026-08 --
|
||||||
|
# bypasses calendar concurrence entirely (every real confessor-not-bishop
|
||||||
|
# saint's Second Vespers turned out to be outranked by an adjacent fixed
|
||||||
|
# feast in 2026: St. Louis by St. Zephyrinus's First Vespers, St. Francis
|
||||||
|
# by SS. Placid and Companions', St. Dominic by Our Lady of the Snows',
|
||||||
|
# St. Nicholas of Tolentino by the Nativity-of-the-BVM octave's -- a
|
||||||
|
# structural pattern across this Common category, not a query mistake),
|
||||||
|
# so the votive-office view was used instead to get the category's true
|
||||||
|
# content directly. See lauds-capitulum-common-of-a-confessor-not-
|
||||||
|
# bishop.yml's header for the fuller note on this bundle's gap; the
|
||||||
|
# chapter itself is byte-identical to the Lauds one (same Sir 31:8-9),
|
||||||
|
# which is why no separate vespers-capitulum-<id> file was authored --
|
||||||
|
# see vespers.ts's vespersCapitulumForOverride, which falls through to
|
||||||
|
# the Lauds file automatically, same as St. Lawrence's own precedent.
|
||||||
|
id: vespers-responsory-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: |
|
||||||
|
R.br. Os justi * Meditábitur sapiéntiam.
|
||||||
|
℟. Os justi * Meditábitur sapiéntiam.
|
||||||
|
℣. Et lingua ejus loquétur judícium.
|
||||||
|
℟. Meditábitur sapiéntiam.
|
||||||
|
℣. Glória Patri, et Fílio, * et Spirítui Sancto.
|
||||||
|
℟. Os justi * Meditábitur sapiéntiam.
|
||||||
|
en: |
|
||||||
|
R.br. The mouth of the righteous * speaketh wisdom.
|
||||||
|
℟. The mouth of the righteous * speaketh wisdom.
|
||||||
|
℣. And his tongue talketh judgment.
|
||||||
|
℟. The righteous speaketh wisdom.
|
||||||
|
℣. Glory be to the Father, and to the Son, * and to the Holy Ghost.
|
||||||
|
℟. The mouth of the righteous * speaketh wisdom.
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Verified against Divinum Officium (Monastic Tridentinum 1617), Vespers,
|
||||||
|
# `votive=C5` live query, 2026-08 -- see vespers-responsory-common-of-a-
|
||||||
|
# confessor-not-bishop.yml's header for why the votive-office view was
|
||||||
|
# used instead of a real saint's own (outranked) Second Vespers.
|
||||||
|
id: vespers-versicle-common-of-a-confessor-not-bishop
|
||||||
|
text:
|
||||||
|
la: "V. Amávit eum Dóminus, et ornávit eum.\nR. Stolam glóriæ índuit eum."
|
||||||
|
en: "V. The Lord loved him and beautified him.\nR. He clothed him with a robe of glory."
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
+20
-22
@@ -21,6 +21,7 @@ import {
|
|||||||
isFerialOrVigil,
|
isFerialOrVigil,
|
||||||
getOfficeOverrideId,
|
getOfficeOverrideId,
|
||||||
resolveResponsory,
|
resolveResponsory,
|
||||||
|
resolveOfficeBundle,
|
||||||
} from './resolve-common';
|
} from './resolve-common';
|
||||||
import laudsDefinitionData from '../data/hours/lauds.yml';
|
import laudsDefinitionData from '../data/hours/lauds.yml';
|
||||||
import laudsAntiphonsData from '../data/hours/lauds-antiphons.yml';
|
import laudsAntiphonsData from '../data/hours/lauds-antiphons.yml';
|
||||||
@@ -178,29 +179,26 @@ function resolvePsalmody(day: LiturgicalDay): ResolvedPart[] {
|
|||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A duplex-majus+/Marian-Saturday override's own capitulum/responsory/
|
/** Any sanctoral winner's (or named-temporal feast's) own capitulum/
|
||||||
* hymn/versicle (data/propers/common/lauds-{part}-${id}.yml), when
|
* responsory/hymn/versicle (data/propers/common/lauds-{part}-${id}.yml),
|
||||||
* authored — most overrides only bother with the psalmody (see
|
* else their Common's (`${part}-${common}`), when authored — see
|
||||||
* getPsalmodyOverrideFor) and leave this bundle at its plain weekday
|
* resolve-common.ts's resolveOfficeBundle for the eligibility/fallback
|
||||||
* default, which is exactly what falls back here when the id-keyed
|
* rule (deliberately rank-agnostic as of 2026-08-25: a simplex feast's
|
||||||
* capitulum doesn't exist (same dual-missing-status "not authored"
|
* Common chapter/hymn is real content, not gated behind duplex-majus+
|
||||||
* signal used throughout this codebase, not a special case). Falls to a
|
* like the psalmody override above is). Falls to a *seasonal* default
|
||||||
* *seasonal* default next (Advent/Lent/Passiontide/Paschaltide — see
|
* next (Advent/Lent/Passiontide/Paschaltide — see resolve-common.ts's
|
||||||
* resolve-common.ts's seasonalOfficeSuffix), and only then the plain
|
* seasonalOfficeSuffix), and only then the plain weekday default — a
|
||||||
* weekday default — a feast's own override always wins over the season
|
* feast's own override always wins over the season it happens to fall
|
||||||
* it happens to fall in, same as everywhere else in this codebase. */
|
* in, same as everywhere else in this codebase. */
|
||||||
function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
||||||
const overrideId = getPsalmodyOverrideFor(day)?.id;
|
const bundle = resolveOfficeBundle('lauds', day);
|
||||||
if (overrideId) {
|
if (bundle) {
|
||||||
const chapter = resolveCommon(`lauds-capitulum-${overrideId}`);
|
return [
|
||||||
if (chapter.status.la !== 'missing' || chapter.status.en !== 'missing') {
|
{ kind: 'chapter', text: bundle.chapter },
|
||||||
return [
|
{ kind: 'responsory', text: bundle.responsory },
|
||||||
{ kind: 'chapter', text: chapter },
|
{ kind: 'hymn', text: bundle.hymn },
|
||||||
{ kind: 'responsory', text: resolveResponsory(resolveCommon(`lauds-responsory-${overrideId}`), day) },
|
{ kind: 'versicle', text: bundle.versicle },
|
||||||
{ kind: 'hymn', text: resolveCommon(`lauds-hymn-${overrideId}`) },
|
];
|
||||||
{ kind: 'versicle', text: resolveCommon(`lauds-versicle-${overrideId}`) },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const seasonSuffix = seasonalOfficeSuffix(day.season);
|
const seasonSuffix = seasonalOfficeSuffix(day.season);
|
||||||
const key = seasonSuffix ?? day.weekday;
|
const key = seasonSuffix ?? day.weekday;
|
||||||
|
|||||||
@@ -401,6 +401,66 @@ export function resolveMinorHourChapter(hourId: string, day: LiturgicalDay, fall
|
|||||||
return resolveCommon(fallbackId);
|
return resolveCommon(fallbackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OfficeBundle {
|
||||||
|
chapter: ResolvedText;
|
||||||
|
responsory: ResolvedText;
|
||||||
|
hymn: ResolvedText;
|
||||||
|
versicle: ResolvedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The chapter/responsory/hymn/versicle bundle following Lauds'/Vespers'
|
||||||
|
* psalmody (hours/lauds.ts's and hours/vespers.ts's own resolveOffice) —
|
||||||
|
* a saint's own proper bundle (`${hourId}-{part}-${id}`) when authored,
|
||||||
|
* else that saint's Common bundle (`${hourId}-{part}-${commonId}`,
|
||||||
|
* SaintRecord's main `common` field, not `minorHoursCommon` — this is the
|
||||||
|
* saint's overall classification, the same one driving their day collect).
|
||||||
|
* Eligibility is deliberately rank-agnostic, `getMinorHourOverrideId`'s
|
||||||
|
* test (any sanctoral winner, or a named ALWAYS_OVERRIDE_TEMPORAL_IDS
|
||||||
|
* feast) rather than resolveOffice's old duplex-majus+-only gate: a
|
||||||
|
* simplex feast's own or Common's chapter/hymn is real, distinct
|
||||||
|
* liturgical content, not something only strong feasts are entitled to —
|
||||||
|
* confirmed 2026-08-25 (St. Louis, King of France, simplex, was silently
|
||||||
|
* falling all the way to the plain ferial default instead of his Common
|
||||||
|
* of a Confessor Not Bishop). Same honest "eligible, not gated on whether
|
||||||
|
* content exists" convention as everywhere else: returns `undefined` when
|
||||||
|
* neither the proper nor the Common has this bundle authored yet, so the
|
||||||
|
* caller falls through to its own seasonal/weekday default.
|
||||||
|
*
|
||||||
|
* `resolveChapterFor` lets Vespers reuse its own chapter lookup (which
|
||||||
|
* itself falls back to the byte-identical Lauds capitulum file when no
|
||||||
|
* `vespers-capitulum-<id>.yml` exists — see vespersCapitulumForOverride)
|
||||||
|
* instead of the plain `${hourId}-capitulum-${id}` default used here.
|
||||||
|
*/
|
||||||
|
export function resolveOfficeBundle(
|
||||||
|
hourId: string,
|
||||||
|
day: LiturgicalDay,
|
||||||
|
resolveChapterFor: (id: string) => ResolvedText = (id) => resolveCommon(`${hourId}-capitulum-${id}`),
|
||||||
|
): OfficeBundle | undefined {
|
||||||
|
const overrideId = getMinorHourOverrideId(day);
|
||||||
|
if (!overrideId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const tryId = (id: string): OfficeBundle | undefined => {
|
||||||
|
const chapter = resolveChapterFor(id);
|
||||||
|
if (chapter.status.la === 'missing' && chapter.status.en === 'missing') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
chapter,
|
||||||
|
responsory: resolveResponsory(resolveCommon(`${hourId}-responsory-${id}`), day),
|
||||||
|
hymn: resolveCommon(`${hourId}-hymn-${id}`),
|
||||||
|
versicle: resolveCommon(`${hourId}-versicle-${id}`),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const proper = tryId(overrideId);
|
||||||
|
if (proper) {
|
||||||
|
return proper;
|
||||||
|
}
|
||||||
|
const commonId = getSaintRecord(overrideId)?.common;
|
||||||
|
return commonId ? tryId(commonId) : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/** Fills a Common collect template's literal `{N}` placeholders with a
|
/** Fills a Common collect template's literal `{N}` placeholders with a
|
||||||
* saint's own name(s) per language (SaintRecord.collectName) — the same
|
* saint's own name(s) per language (SaintRecord.collectName) — the same
|
||||||
* substitution the reference source's own Commune files perform
|
* substitution the reference source's own Commune files perform
|
||||||
|
|||||||
+24
-25
@@ -15,8 +15,8 @@ import {
|
|||||||
verifiedText,
|
verifiedText,
|
||||||
seasonalOfficeSuffix,
|
seasonalOfficeSuffix,
|
||||||
isFerialOrVigil,
|
isFerialOrVigil,
|
||||||
getOfficeOverrideId,
|
|
||||||
resolveResponsory,
|
resolveResponsory,
|
||||||
|
resolveOfficeBundle,
|
||||||
} from './resolve-common';
|
} from './resolve-common';
|
||||||
import vespersDefinitionData from '../data/hours/vespers.yml';
|
import vespersDefinitionData from '../data/hours/vespers.yml';
|
||||||
import vespersAntiphonsData from '../data/hours/vespers-antiphons.yml';
|
import vespersAntiphonsData from '../data/hours/vespers-antiphons.yml';
|
||||||
@@ -109,31 +109,30 @@ function vespersCapitulumForOverride(id: string): ResolvedText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** The chapter/responsory/hymn/versicle bundle following the psalmody —
|
/** The chapter/responsory/hymn/versicle bundle following the psalmody —
|
||||||
* see hours/types.ts's 'vespers-office' doc comment. A duplex-majus+
|
* see hours/types.ts's 'vespers-office' doc comment. Any sanctoral
|
||||||
* saint's own proper bundle (chapter via vespersCapitulumForOverride
|
* winner's (or named-temporal feast's) own proper bundle (chapter via
|
||||||
* above, responsory/hymn/versicle via `vespers-{part}-${id}`), or one of
|
* vespersCapitulumForOverride above, responsory/hymn/versicle via
|
||||||
* the named temporal feasts eligible via resolve-common.ts's
|
* `vespers-{part}-${id}`), else their Common's bundle, wins first when
|
||||||
* getOfficeOverrideId, wins first when authored — same eligible-but-not-
|
* authored — resolve-common.ts's resolveOfficeBundle, deliberately
|
||||||
* gated-on-content pattern as Lauds' resolveOffice, just without a
|
* rank-agnostic (2026-08-25: matches Lauds' identical change, ditto for
|
||||||
* psalmody-override table of its own to piggyback eligibility on
|
* the same reason — a simplex feast's Common office is real content),
|
||||||
* (Vespers has no per-feast psalmody override mechanism — see TODO.md).
|
* not gated at duplex-majus+ the way this hour's lack of its own
|
||||||
* Falls to a *seasonal* default next (Advent/Lent/Passiontide/
|
* psalmody-override table might otherwise suggest (Vespers has no
|
||||||
* Paschaltide — see resolve-common.ts's seasonalOfficeSuffix), and only
|
* per-feast psalmody override mechanism — see TODO.md; that's unrelated
|
||||||
* then the plain weekday default — a feast's own override always wins
|
* to this bundle's own eligibility). Falls to a *seasonal* default next
|
||||||
* over the season it happens to fall in, same as everywhere else in this
|
* (Advent/Lent/Passiontide/Paschaltide — see resolve-common.ts's
|
||||||
* codebase. */
|
* seasonalOfficeSuffix), and only then the plain weekday default — a
|
||||||
|
* feast's own override always wins over the season it happens to fall
|
||||||
|
* in, same as everywhere else in this codebase. */
|
||||||
function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
||||||
const overrideId = getOfficeOverrideId(day);
|
const bundle = resolveOfficeBundle('vespers', day, vespersCapitulumForOverride);
|
||||||
if (overrideId) {
|
if (bundle) {
|
||||||
const chapter = vespersCapitulumForOverride(overrideId);
|
return [
|
||||||
if (chapter.status.la !== 'missing' || chapter.status.en !== 'missing') {
|
{ kind: 'chapter', text: bundle.chapter },
|
||||||
return [
|
{ kind: 'responsory', text: bundle.responsory },
|
||||||
{ kind: 'chapter', text: chapter },
|
{ kind: 'hymn', text: bundle.hymn },
|
||||||
{ kind: 'responsory', text: resolveResponsory(resolveCommon(`vespers-responsory-${overrideId}`), day) },
|
{ kind: 'versicle', text: bundle.versicle },
|
||||||
{ kind: 'hymn', text: resolveCommon(`vespers-hymn-${overrideId}`) },
|
];
|
||||||
{ kind: 'versicle', text: resolveCommon(`vespers-versicle-${overrideId}`) },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const seasonSuffix = seasonalOfficeSuffix(day.season);
|
const seasonSuffix = seasonalOfficeSuffix(day.season);
|
||||||
const key = seasonSuffix ?? day.weekday;
|
const key = seasonSuffix ?? day.weekday;
|
||||||
|
|||||||
Reference in New Issue
Block a user