Add per-feast overrides to Prime/Terce/Sext/None; fill Lauds' own Lawrence office bundle
Deploy / deploy (push) Successful in 51s

Prime/Terce/Sext/None had no per-feast override mechanism at all before
this -- their psalm antiphon always fell back to the plain weekday
default and their chapter was always a single fixed per-annum/per-weekday
text, regardless of what was actually being celebrated, even on a
saint's own actual feast day (not just during an octave). Confirmed live
(Monastic Tridentinum 1617) that St. Lawrence has his own real antiphon
and chapter at every one of these hours, both on his own day and
throughout his octave.

New shared mechanism in hours/resolve-common.ts: getMinorHourOverrideId
(duplex-majus+ threshold, kept in sync with Lauds' own so it's one
shared backlog), resolveMinorHourAntiphon, resolveMinorHourChapter --
all resolveOfficeWinner-aware, so an octave day gets the same override
as the feast's own actual day. Prime additionally needed
isSundayOrFeastOffice (its capitulum/Preces Sunday-vs-ferial choice)
made octave-aware -- live-verified Prime's capitulum stays the
Sunday/feast form throughout the octave too, so no new file was needed
there, just reaching the existing one correctly.

Also fills in Lauds' own still-missing Lawrence office bundle
(capitulum/responsory/hymn/versicle) -- flagged in TODO.md as worth
fixing "even before tackling the other 32" and still not done until now.

Authored real content for St. Lawrence across all five hours from live
queries. The same ~31-saint backlog (TODO.md) now applies uniformly
across Lauds and the four hours fixed here.

Also documents a real, found-not-fixed gap: when two octaves overlap
with no temporal standing to yield to (St. Lawrence's and the
Assumption's genuinely overlap every Aug 16-17), this app currently
picks whichever started first, which happens to match the live engine
on Aug 17 (Lawrence's own elevated final "Octave Day" outranks the
Assumption's ordinary octave-day strength) but only by coincidence, not
a real rank comparison -- proposed design written up in TODO.md pending
a decision on scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-12 08:05:08 -04:00
parent 143244203d
commit 5f4cf33776
21 changed files with 456 additions and 34 deletions
+9 -4
View File
@@ -20,10 +20,15 @@
# - The Pretiosa (the versicle/response said right after the Martyrology
# in choir) is dropped — a deliberate cut, not an oversight.
#
# The capitulum and Preces both use calendar/isSundayOrFeast to pick between
# a Sunday/feast form and a ferial form (see hours/types.ts's 'by-day-kind').
# By explicit choice, the ferial Preces are said on *every* ferial day, not
# just Advent/Lent/vigils/Ember days the way later rubrics restricted them.
# The capitulum and Preces both use hours/resolve-common.ts's
# isSundayOrFeastOffice to pick between a Sunday/feast form and a ferial
# form (see hours/types.ts's 'by-day-kind') — resolveOfficeWinner-aware, so
# a day within a duplex-majus+ saint's own octave (e.g. St. Lawrence's)
# gets the feast form too, not just his own actual day; live-verified
# directly (2026-08-12, day 3 of his octave: still "ex Psalterio secundum
# diem" / 1 Tim 1:17, identical to his own day). By explicit choice, the
# ferial Preces are said on *every* ferial day, not just Advent/Lent/
# vigils/Ember days the way later rubrics restricted them.
#
# The dead-commemoration psalm (129, De profundis) is dropped by explicit
# choice — a deliberate time-saving cut, not an oversight. The intro/close
@@ -0,0 +1,16 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
# live query, St. Lawrence's own day (2026-08-10) -- "Capitulum
# Responsorium Hymnus Versus {ex Commune aut Festo}". Was still falling
# back to the plain weekday default before this (see TODO.md) -- the
# concrete gap that also turned out to affect every day of his own octave
# too (see hours/resolve-common.ts's resolveOfficeWinner).
id: lauds-capitulum-st-lawrence
text:
la: "Fratres: Qui parce séminat, parce et metet; et qui séminat in benedictiónibus, de benedictiónibus et metet."
en: "Brethren: He which soweth sparingly shall reap also sparingly, and he which soweth bountifully shall reap also bountifully."
citation:
la: "2 Cor 9:6"
en: "2 Cor 9:6"
status:
la: verified
en: verified
@@ -0,0 +1,50 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
# live query, St. Lawrence's own day (2026-08-10). "Martyr Dei" --
# self-contained, including its own final doxology stanza.
id: lauds-hymn-st-lawrence
text:
la: |
Martyr Dei, qui únicum
Patris sequéndo Fílium,
Victis triúmphas hóstibus,
Victor fruens cæléstibus.
Tui precátus múnere
Nostrum reátum dílue,
Arcens mali contágium,
Vitæ rémovens tǽdium.
Solúta sunt jam víncula
Tui sacráti córporis:
Nos solve vinclis sǽculi,
Amóre Fílii Dei.
Deo Patri sit glória,
Ejúsque soli Fílio,
Cum Spíritu Paráclito,
Et nunc, et in perpétuum
Amen.
en: |
Martyr of God, whose strength was steeled
To follow close God's only Son,
Well didst thou brave thy battlefield,
And well thy heavenly bliss was won!
Now join thy prayers with ours, who pray
That God may pardon us and bless;
For prayer keeps evil's plague away,
And draws from life its weariness.
Long, long ago, were loosed the chains
That held thy body once in thrall;
For us how many a bond remains!
O love of God release us all.
All praise to God the Father be,
All praise to thee, Eternal Son;
All praise, O Holy Ghost, to thee,
While never-ending ages run.
Amen.
status:
la: verified
en: verified
@@ -0,0 +1,21 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
# live query, St. Lawrence's own day (2026-08-10).
id: lauds-responsory-st-lawrence
text:
la: |
R.br. Glória et honóre * Coronásti eum, Dómine.
R. Glória et honóre * Coronásti eum, Dómine.
V. Et constituísti eum super ópera mánuum tuárum.
R. Coronásti eum, Dómine.
V. Glória Patri, et Fílio, * et Spirítui Sancto.
R. Glória et honóre * Coronásti eum, Dómine.
en: |
R.br. Thou hast crowned him * with glory and honour, O Lord.
R. Thou hast crowned him * with glory and honour, O Lord.
V. And madest him to have dominion over the works of thy hands.
R. Thou hast crowned him.
V. Glory be to the Father, and to the Son, * and to the Holy Ghost.
R. Thou hast crowned him * with glory and honour, O Lord.
status:
la: verified
en: verified
@@ -0,0 +1,9 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Lauds
# live query, St. Lawrence's own day (2026-08-10).
id: lauds-versicle-st-lawrence
text:
la: "V. Dispérsit, dedit paupéribus.\nR. Justítia ejus manet in sǽculum sǽculi."
en: "V. He hath dispersed, he hath given to the poor.\nR. His righteousness endureth for ever."
status:
la: verified
en: verified
@@ -0,0 +1,11 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), None
# live query, St. Lawrence's own day (2026-08-10), also shown on every
# day of his own octave (see hours/resolve-common.ts's
# resolveOfficeWinner).
id: none-antiphon-st-lawrence
text:
la: "Beátus Lauréntius * orábat, dicens: Grátias tibi ago, Dómine, quia jánuas tuas íngredi mérui."
en: "The blessed Lawrence prayed * and said: I give thee thanks, O Lord, that Thou hast made me worthy to enter within thy gates."
status:
la: verified
en: verified
@@ -0,0 +1,14 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), None
# live query, St. Lawrence's own day (2026-08-10) -- "Capitulum Versus
# {ex Proprio Sanctorum}", also shown on every day of his own octave, not
# just his own day (see hours/resolve-common.ts's resolveOfficeWinner).
id: none-capitulum-st-lawrence
text:
la: "Potens est autem Deus omnem grátiam abundáre fácere in vobis, ut, in ómnibus semper omnem sufficiéntiam habéntes, abundétis in omne opus bonum, sicut scriptum est: Dispérsit, dedit paupéribus: justítia ejus manet in sǽculum sǽculi. R. Deo grátias. V. Magna est glória ejus in salutári tuo. R. Glóriam et magnum decórem impónes super eum."
en: "And God is able to make all grace abound in you; that ye always, having all sufficiency in all things, may abound to every good work, As it is written: He hath dispersed abroad, he hath given to the poor: his justice remaineth for ever. R. Thanks be to God. V. His glory is great in thy salvation. R. Honour and great majesty shalt Thou lay upon him."
citation:
la: "2 Cor 9:8-9"
en: "2 Cor 9:8-9"
status:
la: verified
en: verified
@@ -0,0 +1,15 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Prime
# live query, St. Lawrence's own day (2026-08-10), also shown on every
# day of his own octave (see hours/resolve-common.ts's
# resolveOfficeWinner). Prime's own chapter stays "ex Psalterio secundum
# diem" even on his own day -- live-verified it's the same text as the
# existing prime-capitulum-dominica.yml, so no separate override file was
# needed for that, just the Sunday/feast selection reaching this day too
# (see hours/resolve-common.ts's isSundayOrFeastOffice).
id: prime-antiphon-st-lawrence
text:
la: "Lauréntius * ingréssus est Martyr, et conféssus est nomen Dómini Jesu Christi."
en: "Lawrence * went in to be a martyr, and acknowledged the name of our Lord Jesus Christ."
status:
la: verified
en: verified
@@ -0,0 +1,11 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Sext
# live query, St. Lawrence's own day (2026-08-10), also shown on every
# day of his own octave (see hours/resolve-common.ts's
# resolveOfficeWinner).
id: sext-antiphon-st-lawrence
text:
la: "Adhǽsit * ánima mea post te, quia caro mea igne cremáta est pro te, Deus meus."
en: "O my God, my soul cleaveth * fast after thee, for my flesh hath been burnt with fire for thy sake."
status:
la: verified
en: verified
@@ -0,0 +1,14 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Sext
# live query, St. Lawrence's own day (2026-08-10) -- "Capitulum Versus
# {ex Proprio Sanctorum}", also shown on every day of his own octave, not
# just his own day (see hours/resolve-common.ts's resolveOfficeWinner).
id: sext-capitulum-st-lawrence
text:
la: "Unusquísque prout destinávit in corde suo, non ex tristítia aut ex necessitáte; hílarem enim datórem díligit Deus. R. Deo grátias. V. Posuísti, Dómine, super caput ejus. R. Corónam de lápide pretióso."
en: "Every one as he hath determined in his heart, not with sadness, or of necessity: for God loveth a cheerful giver. R. Thanks be to God. V. O Lord, Thou hast set a crown of precious stones. R. Upon his head."
citation:
la: "2 Cor 9:7"
en: "2 Cor 9:7"
status:
la: verified
en: verified
@@ -0,0 +1,11 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Terce
# live query, St. Lawrence's own day (2026-08-10), also shown on every
# day of his own octave (see hours/resolve-common.ts's
# resolveOfficeWinner).
id: terce-antiphon-st-lawrence
text:
la: "Lauréntius * bonum opus operátus est, qui per signum crucis cæcos illuminávit."
en: "Lawrence wrought a good work, * in that with the sign of the Cross he gave sight to the blind."
status:
la: verified
en: verified
@@ -0,0 +1,14 @@
# Verified against Divinum Officium (Monastic Tridentinum 1617), Terce
# live query, St. Lawrence's own day (2026-08-10) -- "Capitulum Versus
# {ex Proprio Sanctorum}", also shown on every day of his own octave, not
# just his own day (see hours/resolve-common.ts's resolveOfficeWinner).
id: terce-capitulum-st-lawrence
text:
la: "Fratres: Qui parce séminat, parce et metet; et qui séminat in benedictiónibus, de benedictiónibus et metet. R. Deo grátias. V. Glória et honóre coronásti eum, Dómine. R. Et constituísti eum super ópera mánuum tuarum."
en: "Brethren: He which soweth sparingly shall reap also sparingly, and he which soweth bountifully shall reap also bountifully. R. Thanks be to God. V. Thou hast crowned him with glory and honour, O Lord. R. And madest him to have dominion over the works of thy hands."
citation:
la: "2 Cor 9:6"
en: "2 Cor 9:6"
status:
la: verified
en: verified
+11 -4
View File
@@ -6,7 +6,14 @@ import { getPsalmsFor } from '../psalter/distribution';
import { getPsalmVerses } from '../psalter';
import { getOpeningVersicleId } from './opening-versicle';
import { isDoubleOrHigher } from './antiphon';
import { resolveCommon, getDayCollect, splitNamedAntiphon } from './resolve-common';
import {
resolveCommon,
getDayCollect,
splitNamedAntiphon,
resolveOfficeWinner,
resolveMinorHourAntiphon,
resolveMinorHourChapter,
} from './resolve-common';
import noneDefinitionData from '../data/hours/none.yml';
import antiphonsData from '../data/hours/none-antiphons.yml';
@@ -21,7 +28,7 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
// Self-contained, no appendDoxology — see none-hymn.yml.
return [{ kind: 'hymn', text: resolveCommon(part.textRef.id) }];
case 'chapter':
return [{ kind: 'chapter', text: resolveCommon(part.textRef.id) }];
return [{ kind: 'chapter', text: resolveMinorHourChapter('none', day, part.textRef.id) }];
case 'day-collect':
return [{ kind: 'prayer', text: getDayCollect(day) }];
case 'preces':
@@ -31,8 +38,8 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
// psalms, no closing repeat (unlike Prime): confirmed directly
// against the engine, Capitulum follows the third psalm immediately.
const psalmRefs = getPsalmsFor('none', day.weekday);
const { incipit, full } = splitNamedAntiphon(antiphons[day.weekday]);
const opening = isDoubleOrHigher(day.winner) ? full : incipit;
const { incipit, full } = splitNamedAntiphon(resolveMinorHourAntiphon('none', day, antiphons[day.weekday]));
const opening = isDoubleOrHigher(resolveOfficeWinner(day)) ? full : incipit;
return psalmRefs.map((ref, i) => ({
kind: 'psalm' as const,
psalmNumber: ref.number,
+17 -12
View File
@@ -1,6 +1,6 @@
import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart } from './types';
import type { LiturgicalDay, Weekday } from '../calendar/types';
import { resolveDay, isSundayOrFeast } from '../calendar';
import { resolveDay } from '../calendar';
import { getDayLabel } from '../calendar/day-label';
import { getPsalmsFor } from '../psalter/distribution';
import { getPsalmVerses } from '../psalter';
@@ -10,7 +10,14 @@ import { getChapterResponsoryId } from './chapter-responsory';
import { getHymnDoxologyId } from './hymn-doxology';
import { getOpeningVersicleId } from './opening-versicle';
import { isDoubleOrHigher } from './antiphon';
import { resolveCommon, appendDoxology, splitNamedAntiphon } from './resolve-common';
import {
resolveCommon,
appendDoxology,
splitNamedAntiphon,
resolveOfficeWinner,
resolveMinorHourAntiphon,
isSundayOrFeastOffice,
} from './resolve-common';
import primeDefinitionData from '../data/hours/prime.yml';
import antiphonsData from '../data/hours/prime-antiphons.yml';
@@ -30,7 +37,7 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
case 'prayer':
return [{ kind: part.kind, text: resolveCommon(part.textRef.id) }];
case 'preces':
if (part.omitOnDouble && isDoubleOrHigher(day.winner)) {
if (part.omitOnDouble && isDoubleOrHigher(resolveOfficeWinner(day))) {
return [];
}
return [{ kind: 'preces', text: resolveCommon(part.textRef.id), label: part.label }];
@@ -42,15 +49,13 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
// Real Divinum Officium's actual inclusion rule tangles together
// rank, commemorations, and version-specific rubrics in a way that
// isn't worth replicating exactly — this is the honest simplification:
// Sunday and not a Double-or-higher feast. Octaves aren't modeled at
// all yet (milestone 4), so they can't suppress it either, same as
// isDoubleOrHigher's own limitation.
if (day.weekday !== 'sunday' || isDoubleOrHigher(day.winner)) {
// Sunday and not a Double-or-higher feast.
if (day.weekday !== 'sunday' || isDoubleOrHigher(resolveOfficeWinner(day))) {
return [];
}
return [{ kind: 'lesson', text: resolveCommon('athanasian-creed'), label: 'Athanasian Creed' }];
case 'closing-antiphon':
return [{ kind: 'antiphon', text: splitNamedAntiphon(antiphons[day.weekday]).full }];
return [{ kind: 'antiphon', text: splitNamedAntiphon(resolveMinorHourAntiphon('prime', day, antiphons[day.weekday])).full }];
case 'variable':
if (part.resolve === 'by-season') {
// Currently only the chapter responsory's verse uses this — see
@@ -59,11 +64,11 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
}
{
const psalmRefs = getPsalmsFor('prime', day.weekday);
const { incipit, full } = splitNamedAntiphon(antiphons[day.weekday]);
const { incipit, full } = splitNamedAntiphon(resolveMinorHourAntiphon('prime', day, antiphons[day.weekday]));
// Full text on a Double-or-higher feast, otherwise just the incipit
// — see hours/antiphon.ts. The full repeat comes later, after the
// Creed (see 'closing-antiphon'), not tacked onto the last psalm.
const opening = isDoubleOrHigher(day.winner) ? full : incipit;
const opening = isDoubleOrHigher(resolveOfficeWinner(day)) ? full : incipit;
return psalmRefs.map((ref, i) => ({
kind: 'psalm' as const,
psalmNumber: ref.number,
@@ -86,10 +91,10 @@ function resolvePart(part: HourPart, date: string, day: LiturgicalDay): Resolved
case 'canticle':
return [{ kind: 'canticle', canticleId: part.canticleId, text: resolveCommon(part.textRef.id) }];
case 'by-day-kind': {
if (part.omitOnDouble && isDoubleOrHigher(day.winner)) {
if (part.omitOnDouble && isDoubleOrHigher(resolveOfficeWinner(day))) {
return [];
}
const ref = isSundayOrFeast(day) ? part.sundayOrFeastRef : part.ferialRef;
const ref = isSundayOrFeastOffice(day) ? part.sundayOrFeastRef : part.ferialRef;
if (part.resolvedKind === 'preces') {
return [{ kind: 'preces', text: resolveCommon(ref.id), label: part.label }];
}
+71 -1
View File
@@ -3,7 +3,7 @@ import type { Commemoration, DayWinner, LiturgicalDay } from '../calendar/types'
import type { ProperText } from '../propers';
import { getCommonProper, getTemporalProper } from '../propers';
import { getSaintRecord } from '../calendar/feasts';
import { activeOctavesFor } from '../calendar';
import { activeOctavesFor, isAtLeast } from '../calendar';
import { splitAntiphon } from './antiphon';
function toResolvedText(proper: ProperText): ResolvedText {
@@ -69,6 +69,76 @@ export function resolveOfficeWinner(day: LiturgicalDay): DayWinner {
return day.winner;
}
/** Like calendar/index.ts's own isSundayOrFeast, but resolveOfficeWinner-
* aware — an octave day counts as a "feast" for this purpose too.
* Live-verified: Prime's capitulum/Preces stay in the Sunday/feast form
* throughout St. Lawrence's octave (2026-08-12), not just his own actual
* day (2026-08-10) — both show the identical "ex Psalterio secundum
* diem" 1 Tim 1:17 text. Deliberately a separate function, not a
* replacement for the plain isSundayOrFeast: Lauds' own Cross-suffrage
* gate (hours/lauds.ts) needs the *narrower*, non-office-aware version,
* since Marian Saturday and an octave day both need to land on the
* ferial side there despite not being Sunday or a sanctoral `day.winner`
* either. */
export function isSundayOrFeastOffice(day: LiturgicalDay): boolean {
return day.weekday === 'sunday' || resolveOfficeWinner(day).kind === 'sanctoral';
}
/**
* Whether today's office winner (resolveOfficeWinner) is a strong enough
* feast to carry its own proper minor-hour content (antiphon + chapter)
* — duplex-majus+, the same threshold Lauds' own psalmody override uses
* (hours/lauds.ts's getPsalmodyOverrideFor), kept in sync deliberately:
* as each remaining duplex-majus+ saint gets a Lauds override authored,
* the same id is what Prime/Terce/Sext/None would look for too, so it's
* one shared backlog (see TODO.md), not per-hour lists that can drift.
* Returns the id to look up (`${hourId}-antiphon-${id}` etc.), or
* `undefined` when nothing eligible is happening today.
*/
export function getMinorHourOverrideId(day: LiturgicalDay): string | undefined {
const winner = resolveOfficeWinner(day);
if (winner.kind === 'sanctoral' && isAtLeast(winner.rank, 'duplex-majus')) {
return winner.id;
}
return undefined;
}
/** A Little Hour's (or Prime's) plain per-weekday antiphon, overridden by
* a duplex-majus+ feast's own proper (`${hourId}-antiphon-${id}`) when
* authored — same honest "not gated behind whether content exists, just
* eligible to override at all" fallback as every other override in this
* codebase: an eligible feast without one authored yet just falls
* through to the plain weekday default silently. */
export function resolveMinorHourAntiphon(
hourId: string,
day: LiturgicalDay,
weekdayDefault: Partial<Record<string, string>>,
): Partial<Record<string, string>> {
const overrideId = getMinorHourOverrideId(day);
if (overrideId) {
const proper = getCommonProper(`${hourId}-antiphon-${overrideId}`);
if (proper.status.la !== 'missing' || proper.status.en !== 'missing') {
return proper.text;
}
}
return weekdayDefault;
}
/** Same idea as resolveMinorHourAntiphon, for the chapter
* (`${hourId}-capitulum-${id}`) — falls back to `fallbackId` (the plain
* per-annum/per-weekday one already in place for that hour) when no
* override is eligible, or none has been authored yet for one that is. */
export function resolveMinorHourChapter(hourId: string, day: LiturgicalDay, fallbackId: string): ResolvedText {
const overrideId = getMinorHourOverrideId(day);
if (overrideId) {
const proper = resolveCommon(`${hourId}-capitulum-${overrideId}`);
if (proper.status.la !== 'missing' || proper.status.en !== 'missing') {
return proper;
}
}
return resolveCommon(fallbackId);
}
/**
* The day's own collect — real for the vast majority of days (a temporal
* winner always resolves, since all 52 Sunday collects are authored and
+11 -4
View File
@@ -6,7 +6,14 @@ import { getPsalmsFor } from '../psalter/distribution';
import { getPsalmVerses } from '../psalter';
import { getOpeningVersicleId } from './opening-versicle';
import { isDoubleOrHigher } from './antiphon';
import { resolveCommon, getDayCollect, splitNamedAntiphon } from './resolve-common';
import {
resolveCommon,
getDayCollect,
splitNamedAntiphon,
resolveOfficeWinner,
resolveMinorHourAntiphon,
resolveMinorHourChapter,
} from './resolve-common';
import sextDefinitionData from '../data/hours/sext.yml';
import antiphonsData from '../data/hours/sext-antiphons.yml';
@@ -21,7 +28,7 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
// Self-contained, no appendDoxology — see sext-hymn.yml.
return [{ kind: 'hymn', text: resolveCommon(part.textRef.id) }];
case 'chapter':
return [{ kind: 'chapter', text: resolveCommon(part.textRef.id) }];
return [{ kind: 'chapter', text: resolveMinorHourChapter('sext', day, part.textRef.id) }];
case 'day-collect':
return [{ kind: 'prayer', text: getDayCollect(day) }];
case 'preces':
@@ -31,8 +38,8 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
// psalms, no closing repeat (unlike Prime): confirmed directly
// against the engine, Capitulum follows the third psalm immediately.
const psalmRefs = getPsalmsFor('sext', day.weekday);
const { incipit, full } = splitNamedAntiphon(antiphons[day.weekday]);
const opening = isDoubleOrHigher(day.winner) ? full : incipit;
const { incipit, full } = splitNamedAntiphon(resolveMinorHourAntiphon('sext', day, antiphons[day.weekday]));
const opening = isDoubleOrHigher(resolveOfficeWinner(day)) ? full : incipit;
return psalmRefs.map((ref, i) => ({
kind: 'psalm' as const,
psalmNumber: ref.number,
+11 -4
View File
@@ -6,7 +6,14 @@ import { getPsalmsFor } from '../psalter/distribution';
import { getPsalmVerses } from '../psalter';
import { getOpeningVersicleId } from './opening-versicle';
import { isDoubleOrHigher } from './antiphon';
import { resolveCommon, getDayCollect, splitNamedAntiphon } from './resolve-common';
import {
resolveCommon,
getDayCollect,
splitNamedAntiphon,
resolveOfficeWinner,
resolveMinorHourAntiphon,
resolveMinorHourChapter,
} from './resolve-common';
import terceDefinitionData from '../data/hours/terce.yml';
import antiphonsData from '../data/hours/terce-antiphons.yml';
@@ -21,7 +28,7 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
// Self-contained, no appendDoxology — see terce-hymn.yml.
return [{ kind: 'hymn', text: resolveCommon(part.textRef.id) }];
case 'chapter':
return [{ kind: 'chapter', text: resolveCommon(part.textRef.id) }];
return [{ kind: 'chapter', text: resolveMinorHourChapter('terce', day, part.textRef.id) }];
case 'day-collect':
return [{ kind: 'prayer', text: getDayCollect(day) }];
case 'preces':
@@ -31,8 +38,8 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
// psalms, no closing repeat (unlike Prime): confirmed directly
// against the engine, Capitulum follows the third psalm immediately.
const psalmRefs = getPsalmsFor('terce', day.weekday);
const { incipit, full } = splitNamedAntiphon(antiphons[day.weekday]);
const opening = isDoubleOrHigher(day.winner) ? full : incipit;
const { incipit, full } = splitNamedAntiphon(resolveMinorHourAntiphon('terce', day, antiphons[day.weekday]));
const opening = isDoubleOrHigher(resolveOfficeWinner(day)) ? full : incipit;
return psalmRefs.map((ref, i) => ({
kind: 'psalm' as const,
psalmNumber: ref.number,