Let a sanctoral winner's proper Matins psalmody win over a Sunday's
resolveOrdo's Sunday-nocturn branch fired unconditionally whenever day.weekday === 'sunday', regardless of who actually won the day -- silently making any saint's own proper Matins psalmody override (getMatinsSaintOverride) unreachable on a Sunday, even when authored. The source's own "Psalmi Dominica" rubric line reads as if the plain Sunday psalm cursus always applies whenever a Duplex+ feast wins over a Sunday, but live-querying All Saints (Nov 1, 2026, a Sunday that year) shows it actually has its own distinct proper psalms (Ps 1/4/8, 14/23/ 31, 33/60/96, each its own antiphon) -- not the plain Sunday Nocturn psalms this app was falling back to. Checks for a sanctoral proper override before the Sunday branch now. That override's own Nocturn 3 is psalms, not the 3-OT-canticle shape every other saint/category file uses -- added renderOverrideNocturn3 to dispatch on which field is actually populated instead of assuming canticles unconditionally (which produced a silently empty antiphon and no content). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGsATZvfnpQ81HQuoF5JuL
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
# Live-verified against Divinum Officium (Monastic Tridentinum 1617,
|
||||||
|
# command=prayMatutinum, 2026-11-01, clean year). The source file's own
|
||||||
|
# [Rule] line ("Psalmi Dominica") reads as if the plain Sunday psalm
|
||||||
|
# cursus applies, but that's misleading -- the live render shows a real,
|
||||||
|
# distinct proper set (Ps 1/4/8, 14/23/31, 33/60/96, each psalm its own
|
||||||
|
# All-Saints-themed antiphon, not one antiphon shared per nocturn), not
|
||||||
|
# the plain Sunday Nocturn psalms this app was falling back to before
|
||||||
|
# this file existed. Versicles read directly from the live render,
|
||||||
|
# immediately before each Nocturn's own Pater Noster.
|
||||||
|
id: all-saints
|
||||||
|
nocturn1:
|
||||||
|
groups:
|
||||||
|
- psalms: [1]
|
||||||
|
antiphon:
|
||||||
|
la: "Novit Dóminus * viam iustórum, qui in lege ejus meditántur die ac nocte."
|
||||||
|
en: "The Lord knoweth the way of the righteous, * who in His Law do meditate day and night."
|
||||||
|
- psalms: [4]
|
||||||
|
antiphon:
|
||||||
|
la: "Mirificávit * Dóminus Sanctos suos, et exaudívit eos clamántes ad se."
|
||||||
|
en: "The Lord hath set apart for Himself them that are holy, * and when they called, He hath heard them."
|
||||||
|
- psalms: [8]
|
||||||
|
antiphon:
|
||||||
|
la: "Admirábile est * nomen tuum, Dómine: quia glória et honóre coronásti Sanctos tuos, et constituísti eos super ópera mánuum tuárum."
|
||||||
|
en: "How excellent is thy Name, O Lord, Who hast crowned thy Saints with glory and honour, * and madest them to have dominion over the works of thy hands."
|
||||||
|
versicle:
|
||||||
|
v:
|
||||||
|
la: "Lætámini in Dómino, et exsultáte justi."
|
||||||
|
en: "Be glad in the Lord, and rejoice, ye righteous."
|
||||||
|
r:
|
||||||
|
la: "Et gloriámini omnes recti corde."
|
||||||
|
en: "And glory, all ye that are upright in heart."
|
||||||
|
nocturn2:
|
||||||
|
groups:
|
||||||
|
- psalms: [14]
|
||||||
|
antiphon:
|
||||||
|
la: "Dómine, * qui operáti sunt justítiam, habitábunt in tabernáculo tuo, et requiéscent in monte sancto tuo."
|
||||||
|
en: "They that work righteousness, * O Lord, even they, shall abide in thy tabernacle, and dwell in thy holy Hill."
|
||||||
|
- psalms: [23]
|
||||||
|
antiphon:
|
||||||
|
la: "Hæc est generátio * quæréntium Dóminum, quæréntium fáciem Dei Iacob."
|
||||||
|
en: "This is the generation of them that seek the Lord, * that seek the face of the God of Jacob."
|
||||||
|
- psalms: [31]
|
||||||
|
antiphon:
|
||||||
|
la: "Lætámini in Dómino, * et exsultáte justi, et gloriámini omnes recti corde."
|
||||||
|
en: "Be glad in the Lord, and rejoice, ye righteous, * and shout for joy, all ye that are upright in heart."
|
||||||
|
versicle:
|
||||||
|
v:
|
||||||
|
la: "Exsúltent justi in conspéctu Dei."
|
||||||
|
en: "Let the righteous rejoice before God."
|
||||||
|
r:
|
||||||
|
la: "Et delecténtur in lætítia."
|
||||||
|
en: "Yea, let them exceedingly rejoice."
|
||||||
|
nocturn3:
|
||||||
|
groups:
|
||||||
|
- psalms: [33]
|
||||||
|
antiphon:
|
||||||
|
la: "Timéte Dóminum * omnes Sancti ejus, quóniam nihil deest timéntibus eum: ecce óculi Dómini super justos, et aures ejus ad preces eórum."
|
||||||
|
en: "O fear the Lord, all ye His Saints, * for there is no want to them that fear Him. Behold, the eyes of the Lord are upon the righteous, and His ears are open unto their cry."
|
||||||
|
- psalms: [60]
|
||||||
|
antiphon:
|
||||||
|
la: "Dómine, spes Sanctórum * et turris fortitúdinis eórum, dedísti hereditátem timéntibus nomen tuum, et habitábunt in tabernáculo tuo in sǽcula."
|
||||||
|
en: "O Lord, Thou hast been a shelter for thy Saints, * a strong tower from the enemy. Thou hast given the heritage to those that fear thy Name, and they shall abide in thy tabernacle for ever."
|
||||||
|
- psalms: [96]
|
||||||
|
antiphon:
|
||||||
|
la: "Qui dilígitis Dóminum, * lætámini in Dómino, et confitémini memóriæ sanctitátis ejus."
|
||||||
|
en: "Ye that love the Lord, rejoice in the Lord, * and give thanks at the remembrance of His holiness."
|
||||||
|
versicle:
|
||||||
|
v:
|
||||||
|
la: "Justi autem in perpétuum vivent."
|
||||||
|
en: "The righteous live for evermore."
|
||||||
|
r:
|
||||||
|
la: "Et apud Dóminum est merces eórum."
|
||||||
|
en: "Their reward also is with the Lord."
|
||||||
+41
-3
@@ -389,6 +389,18 @@ function sundayCanticleNocturn(group: SundayNocturn, day: LiturgicalDay): Resolv
|
|||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A per-feast/per-Common Nocturn 3 override is normally the 3-OT-
|
||||||
|
* canticle shape (`sundayCanticleNocturn`) every existing saint/category
|
||||||
|
* file uses — but a real exception exists (All Saints, live-verified
|
||||||
|
* 2026-09-05: Ps 33/60/96, each its own antiphon, not canticles at all).
|
||||||
|
* Dispatches on which field the override actually populated rather than
|
||||||
|
* assuming canticles unconditionally, so a `groups`-shaped Nocturn 3
|
||||||
|
* renders as real psalms via `sundayPsalmNocturn` instead of silently
|
||||||
|
* producing an empty antiphon and no content. */
|
||||||
|
function renderOverrideNocturn3(group: SundayNocturn, day: LiturgicalDay): ResolvedPart[] {
|
||||||
|
return group.groups ? sundayPsalmNocturn(group, day) : sundayCanticleNocturn(group, day);
|
||||||
|
}
|
||||||
|
|
||||||
/** The Matins hymn — a duplex-majus+ saint's or eligible named temporal
|
/** The Matins hymn — a duplex-majus+ saint's or eligible named temporal
|
||||||
* feast's own proper hymn (`matins-hymn-${overrideId}`, via the same
|
* feast's own proper hymn (`matins-hymn-${overrideId}`, via the same
|
||||||
* getOfficeOverrideId eligibility Lauds/Vespers' own resolveOffice uses),
|
* getOfficeOverrideId eligibility Lauds/Vespers' own resolveOffice uses),
|
||||||
@@ -1082,7 +1094,33 @@ export function resolveOrdo(date: string): ResolvedOrdo {
|
|||||||
{ kind: 'hymn', text: resolveMatinsHymn(day) },
|
{ kind: 'hymn', text: resolveMatinsHymn(day) },
|
||||||
];
|
];
|
||||||
|
|
||||||
if (threeNocturns && (day.weekday === 'sunday' || hasTemporalNamedOverride)) {
|
// A sanctoral winner's own proper Matins psalmody takes precedence even
|
||||||
|
// on a Sunday — live-verified 2026-09-05 (All Saints, Nov 1, a Sunday
|
||||||
|
// that year): the source's own "Psalmi Dominica" rubric line reads as
|
||||||
|
// if the plain Sunday psalm cursus always applies whenever a Duplex+
|
||||||
|
// feast wins over a Sunday, but that's misleading — the live render
|
||||||
|
// shows All Saints' own distinct proper psalms (Ps 1/4/8, 14/23/31,
|
||||||
|
// 33/60/96), not the plain Sunday Nocturn psalms. Checked ahead of the
|
||||||
|
// `day.weekday === 'sunday'` branch below, which otherwise unconditionally
|
||||||
|
// wins regardless of who the day's winner is — silently making any
|
||||||
|
// saint's own proper Matins psalmody unreachable on a Sunday. Proper
|
||||||
|
// only (not Common-category) for now: no live-verified case yet
|
||||||
|
// confirms a Common's own Matins psalmody should win over a Sunday's,
|
||||||
|
// unlike a saint's own genuinely proper content.
|
||||||
|
const sundaySanctoralProperOverride = day.weekday === 'sunday' && winner.kind === 'sanctoral' ? getMatinsSaintOverride(winner.id) : undefined;
|
||||||
|
if (sundaySanctoralProperOverride) {
|
||||||
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
||||||
|
parts.push(...sundayPsalmNocturn(sundaySanctoralProperOverride.nocturn1, day));
|
||||||
|
parts.push(...(nocturn1Readings ?? []));
|
||||||
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[1]}` });
|
||||||
|
parts.push(...sundayPsalmNocturn(sundaySanctoralProperOverride.nocturn2, day));
|
||||||
|
parts.push(...(nocturn2Readings ?? []));
|
||||||
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[2]}` });
|
||||||
|
parts.push(...renderOverrideNocturn3(sundaySanctoralProperOverride.nocturn3, day));
|
||||||
|
parts.push(...(nocturn3Readings ?? []));
|
||||||
|
parts.push({ kind: 'te-deum', text: resolveCommon('te-deum') });
|
||||||
|
parts.push({ kind: 'versicle', text: resolveCommon('te-decet-laus') });
|
||||||
|
} else if (threeNocturns && (day.weekday === 'sunday' || hasTemporalNamedOverride)) {
|
||||||
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
||||||
parts.push(...sundayPsalmNocturn(sundayNocturnFor('nocturn1', day, temporalId), day));
|
parts.push(...sundayPsalmNocturn(sundayNocturnFor('nocturn1', day, temporalId), day));
|
||||||
parts.push(...(nocturn1Readings ?? []));
|
parts.push(...(nocturn1Readings ?? []));
|
||||||
@@ -1121,7 +1159,7 @@ export function resolveOrdo(date: string): ResolvedOrdo {
|
|||||||
parts.push(...sundayPsalmNocturn(properOverride.nocturn2, day));
|
parts.push(...sundayPsalmNocturn(properOverride.nocturn2, 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(properOverride.nocturn3, day));
|
parts.push(...renderOverrideNocturn3(properOverride.nocturn3, day));
|
||||||
parts.push(...(nocturn3Readings ?? []));
|
parts.push(...(nocturn3Readings ?? []));
|
||||||
} else if (isAboveDuplex && commonOverride) {
|
} else if (isAboveDuplex && commonOverride) {
|
||||||
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
parts.push({ kind: 'section-heading', label: `Nocturn ${NOCTURN_NUMERAL[0]}` });
|
||||||
@@ -1131,7 +1169,7 @@ export function resolveOrdo(date: string): ResolvedOrdo {
|
|||||||
parts.push(...sundayPsalmNocturn(commonOverride.nocturn2, day));
|
parts.push(...sundayPsalmNocturn(commonOverride.nocturn2, 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(commonOverride.nocturn3, day));
|
parts.push(...renderOverrideNocturn3(commonOverride.nocturn3, day));
|
||||||
parts.push(...(nocturn3Readings ?? []));
|
parts.push(...(nocturn3Readings ?? []));
|
||||||
} else {
|
} else {
|
||||||
const commonId = !isAboveDuplex && winner.kind === 'sanctoral' ? getSaintRecord(winner.id)?.minorHoursCommon : undefined;
|
const commonId = !isAboveDuplex && winner.kind === 'sanctoral' ? getSaintRecord(winner.id)?.minorHoursCommon : undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user