Drop Matins' opening (versicle, Ps 3, Invitatory, hymn) during the Sacred Triduum
Tenebrae's rubric replaces Matins' usual opening with a silently-said Pater/Ave/Credo, live-verified against both Monastic Tridentinum 1617 and Divino Afflatu 1954 (Holy Thursday: Invitatorium and Hymnus both "omittitur", no Ps 3 or versicle either). Since this app already never renders that silent block on ordinary days either (data/hours/prime.yml), the fix is a pure omission straight into Nocturn 1, using the same isInTriduum window added for the Gloria Patri work.
This commit is contained in:
+12
-1
@@ -63,6 +63,7 @@
|
||||
import type { ResolvedOrdo, ResolvedPart, ResolvedVerse } from './types';
|
||||
import type { LiturgicalDay } from '../calendar/types';
|
||||
import { resolveDay, resolveTemporalId, activeOctavesFor } from '../calendar';
|
||||
import { isInTriduum } from '../calendar/temporal';
|
||||
import { getDayLabel } from '../calendar/day-label';
|
||||
import { getPsalmVerses } from '../psalter';
|
||||
import { getPsalmsFor, type PsalmRef } from '../psalter/distribution';
|
||||
@@ -301,7 +302,17 @@ export function resolveOrdo(date: string): ResolvedOrdo {
|
||||
const pool = buildReadingPool(day, temporalId, date);
|
||||
const [nocturn1Readings, nocturn2Readings, nocturn3Readings] = distributeIntoNocturns(pool, threeNocturns ? 3 : 1);
|
||||
|
||||
const parts: ResolvedPart[] = [
|
||||
// Tenebrae's real rubric: during the Sacred Triduum the whole opening
|
||||
// (versicle, Ps 3, Invitatory, hymn) is dropped, replaced by a silently-
|
||||
// said Pater/Ave/Credo — live-verified against both Monastic Tridentinum
|
||||
// 1617 and Divino Afflatu 1954 (Holy Thursday: "Invitatorium{omittitur}",
|
||||
// "Hymnus{omittitur}", no Ps 3 or versicle either). This app already
|
||||
// never renders that silent Pater/Ave/Credo elsewhere (see
|
||||
// data/hours/prime.yml's own header: dropped "to keep the hour
|
||||
// shorter"), so the fix here is a pure omission, not a new part kind.
|
||||
const parts: ResolvedPart[] = isInTriduum(day.date)
|
||||
? []
|
||||
: [
|
||||
{ kind: 'versicle', text: resolveCommon(getOpeningVersicleId(day.season, day.winner)) },
|
||||
plainPsalm(3),
|
||||
{ kind: 'section-heading', label: 'Invitatory' },
|
||||
|
||||
@@ -299,3 +299,36 @@ describe('resolveOrdo("matins", ...) second Duplex+ weekday-feast proof — St.
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveOrdo("matins", ...) Sacred Triduum', () => {
|
||||
// Tenebrae's real rubric drops the whole opening (versicle, Ps 3,
|
||||
// Invitatory, hymn) in favor of a silently-said Pater/Ave/Credo —
|
||||
// live-verified against both Monastic Tridentinum 1617 and Divino
|
||||
// Afflatu 1954 (Holy Thursday: "Invitatorium{omittitur}",
|
||||
// "Hymnus{omittitur}", no Ps 3 or versicle either). This app never
|
||||
// renders that silent block anywhere (see data/hours/prime.yml's own
|
||||
// header), so the fix is a pure omission -- straight into Nocturn 1.
|
||||
const HOLY_THURSDAY = '2026-04-02';
|
||||
const GOOD_FRIDAY = '2026-04-03';
|
||||
const HOLY_SATURDAY = '2026-04-04';
|
||||
|
||||
it.each([HOLY_THURSDAY, GOOD_FRIDAY, HOLY_SATURDAY])('drops the opening versicle/Ps 3/Invitatory/hymn on %s', (date) => {
|
||||
const ordo = resolveOrdo('matins', date);
|
||||
expect(ordo.parts.some((p) => p.kind === 'versicle')).toBe(false);
|
||||
expect(ordo.parts.some((p) => p.kind === 'psalm' && p.psalmNumber === 3)).toBe(false);
|
||||
expect(ordo.parts.some((p) => p.kind === 'psalm' && p.psalmNumber === 94)).toBe(false);
|
||||
expect(ordo.parts.some((p) => p.kind === 'section-heading' && p.label === 'Invitatory')).toBe(false);
|
||||
expect(ordo.parts.some((p) => p.kind === 'hymn')).toBe(false);
|
||||
});
|
||||
|
||||
it('goes straight into Nocturn 1 psalmody as the very first part', () => {
|
||||
const ordo = resolveOrdo('matins', HOLY_THURSDAY);
|
||||
expect(ordo.parts[0]?.kind).toBe('psalm');
|
||||
});
|
||||
|
||||
it("leaves an ordinary day's opening block untouched", () => {
|
||||
const ordo = resolveOrdo('matins', '2026-08-20');
|
||||
expect(ordo.parts[0]?.kind).toBe('versicle');
|
||||
expect(ordo.parts[1]).toMatchObject({ kind: 'psalm', psalmNumber: 3 });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user