Label Matins nocturns and the Invitatory in the rendered ordo
Deploy / deploy (push) Successful in 1m17s

Adds a section-heading ResolvedPart kind and emits "Invitatory" and
"Nocturn I/II/III" headings in matins.ts, so the hour's structural
boundaries are visible instead of rendering as one undifferentiated
stream of parts. Ferial (1-nocturn) days get no Nocturn heading, matching
their existing single-unnumbered-nocturn design.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 05:28:44 -04:00
parent e7bbc7c9f5
commit a9f673fef9
5 changed files with 31 additions and 2 deletions
+3 -2
View File
@@ -24,8 +24,9 @@ describe('resolveOrdo("matins", ...) ferial (1-nocturn) branch', () => {
it('opens with the Deus in adjutorium versicle, then Psalm 3, then the Invitatory (Psalm 94)', () => {
expect(ordo.parts[0]?.kind).toBe('versicle');
expect(ordo.parts[1]).toMatchObject({ kind: 'psalm', psalmNumber: 3 });
expect(ordo.parts[2]).toMatchObject({ kind: 'psalm', psalmNumber: 94 });
const invitatoryAntiphon = (ordo.parts[2] as { antiphon?: { text: Record<string, string> } }).antiphon;
expect(ordo.parts[2]).toMatchObject({ kind: 'section-heading', label: 'Invitatory' });
expect(ordo.parts[3]).toMatchObject({ kind: 'psalm', psalmNumber: 94 });
const invitatoryAntiphon = (ordo.parts[3] as { antiphon?: { text: Record<string, string> } }).antiphon;
expect(invitatoryAntiphon?.text.la).toContain('Veníte');
// Real practice repeats the invitatory antiphon between verse groups —
// deliberately not modeled that way here (see hours/matins.ts's own