Fix Matins test part-index offsets for new opening versicle
Deploy / deploy (push) Successful in 1m28s

Inserting the new Domine-labia versicle shifted every downstream
ordo.parts index/destructure by one. Pure index-shift fixups, no
behavioral assertions changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yHHNsbzD8jLkkmVuJpAcC
This commit is contained in:
2026-09-02 05:54:15 -04:00
parent db23523a5d
commit 3f9b748e4a
+21 -18
View File
@@ -22,12 +22,13 @@ describe('resolveOrdo("matins", ...) ferial (1-nocturn) branch', () => {
expect(ordo.notImplemented).toBeUndefined(); expect(ordo.notImplemented).toBeUndefined();
}); });
it('opens with the Deus in adjutorium versicle, then Psalm 3, then the Invitatory (Psalm 94)', () => { it('opens with the Deus in adjutorium versicle, then Domine labia (x3), then Psalm 3, then the Invitatory (Psalm 94)', () => {
expect(ordo.parts[0]?.kind).toBe('versicle'); expect(ordo.parts[0]?.kind).toBe('versicle');
expect(ordo.parts[1]).toMatchObject({ kind: 'psalm', psalmNumber: 3 }); expect(ordo.parts[1]?.kind).toBe('versicle');
expect(ordo.parts[2]).toMatchObject({ kind: 'section-heading', label: 'Invitatory' }); expect(ordo.parts[2]).toMatchObject({ kind: 'psalm', psalmNumber: 3 });
expect(ordo.parts[3]).toMatchObject({ kind: 'psalm', psalmNumber: 94 }); expect(ordo.parts[3]).toMatchObject({ kind: 'section-heading', label: 'Invitatory' });
const invitatoryAntiphon = (ordo.parts[3] as { antiphon?: { text: Record<string, string> } }).antiphon; expect(ordo.parts[4]).toMatchObject({ kind: 'psalm', psalmNumber: 94 });
const invitatoryAntiphon = (ordo.parts[4] as { antiphon?: { text: Record<string, string> } }).antiphon;
expect(invitatoryAntiphon?.text.la).toContain('Veníte'); expect(invitatoryAntiphon?.text.la).toContain('Veníte');
// Real practice repeats the invitatory antiphon between verse groups — // Real practice repeats the invitatory antiphon between verse groups —
// deliberately not modeled that way here (see hours/matins.ts's own // deliberately not modeled that way here (see hours/matins.ts's own
@@ -48,8 +49,8 @@ describe('resolveOrdo("matins", ...) ferial (1-nocturn) branch', () => {
}); });
it("gives every nocturn psalm its own antiphon and includes Tuesday's own versicle (data/hours/matins-ferial-antiphons.yml)", () => { it("gives every nocturn psalm its own antiphon and includes Tuesday's own versicle (data/hours/matins-ferial-antiphons.yml)", () => {
// The nocturn's own psalms start at index 4 (after versicle/Ps3/heading/Ps94). // The nocturn's own psalms start at index 5 (after the two opening versicles/Ps3/heading/Ps94).
const nocturnPsalms = ordo.parts.slice(4).filter((p) => p.kind === 'psalm') as { const nocturnPsalms = ordo.parts.slice(5).filter((p) => p.kind === 'psalm') as {
psalmNumber: number; psalmNumber: number;
antiphon?: { text: Record<string, string> }; antiphon?: { text: Record<string, string> };
}[]; }[];
@@ -64,7 +65,7 @@ describe('resolveOrdo("matins", ...) ferial (1-nocturn) branch', () => {
expect(p.antiphon.text.en).toBeTruthy(); expect(p.antiphon.text.en).toBeTruthy();
} }
} }
const nocturnVersicles = ordo.parts.slice(4).filter((p) => p.kind === 'versicle'); const nocturnVersicles = ordo.parts.slice(5).filter((p) => p.kind === 'versicle');
expect(nocturnVersicles).toHaveLength(1); expect(nocturnVersicles).toHaveLength(1);
const versicleText = (nocturnVersicles[0] as { text: { text: Record<string, string> } }).text.text; const versicleText = (nocturnVersicles[0] as { text: { text: Record<string, string> } }).text.text;
expect(versicleText.la).toContain('Ímmola Deo sacrifícium laudis'); expect(versicleText.la).toContain('Ímmola Deo sacrifícium laudis');
@@ -138,15 +139,16 @@ describe('resolveOrdo("matins", ...) Sunday (3-nocturn) branch', () => {
it('renders each nocturn versicle with both its V. and R. lines (real bug: sundayPsalmNocturn/sundayCanticleNocturn used to drop the R. line entirely)', () => { it('renders each nocturn versicle with both its V. and R. lines (real bug: sundayPsalmNocturn/sundayCanticleNocturn used to drop the R. line entirely)', () => {
const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[]; const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[];
// Opening Deus-in-adjutorium versicle + one per nocturn (1, 2, 3) + // Opening Deus-in-adjutorium versicle + opening Domine-labia versicle +
// the closing "Te decet laus" versicle after the Te Deum (2026-08). // one per nocturn (1, 2, 3) + the closing "Te decet laus" versicle
expect(versicles).toHaveLength(5); // after the Te Deum (2026-08).
const [, nocturn1, nocturn2, nocturn3] = versicles; expect(versicles).toHaveLength(6);
const [, , nocturn1, nocturn2, nocturn3] = versicles;
expect(nocturn1?.text.text.la).toBe('V. Memor fui nocte nóminis tui Dómine.\nR. Et custodívi legem tuam.'); expect(nocturn1?.text.text.la).toBe('V. Memor fui nocte nóminis tui Dómine.\nR. Et custodívi legem tuam.');
expect(nocturn2?.text.text.la).toBe('V. Média nocte surgébam ad confiténdum tibi.\nR. Super justítia justificatiónis tuæ.'); expect(nocturn2?.text.text.la).toBe('V. Média nocte surgébam ad confiténdum tibi.\nR. Super justítia justificatiónis tuæ.');
expect(nocturn3?.text.text.la).toBe('V. Exaltáre Dómine in virtúte tua.\nR. Cantábimus et psallémus virtútes tuas.'); expect(nocturn3?.text.text.la).toBe('V. Exaltáre Dómine in virtúte tua.\nR. Cantábimus et psallémus virtútes tuas.');
// The 5th versicle is "Te decet laus", right after the Te Deum (2026-08). // The 6th versicle is "Te decet laus", right after the Te Deum (2026-08).
expect(versicles[4]?.text.text.la).toContain('Te decet laus'); expect(versicles[5]?.text.text.la).toContain('Te decet laus');
}); });
it("resolves the user's own bible-plan reading (Tobit/Sirach) for Nocturn 1", () => { it("resolves the user's own bible-plan reading (Tobit/Sirach) for Nocturn 1", () => {
@@ -260,7 +262,7 @@ describe('resolveOrdo("matins", ...) Advent Sunday Nocturns I-III seasonal overr
); );
const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[]; const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[];
const [, nocturn1, nocturn2, nocturn3] = versicles; const [, , nocturn1, nocturn2, nocturn3] = versicles;
expect(nocturn1?.text.text.la).toBe('V. Ex Sion spécies decóris ejus.\nR. Deus noster maniféste véniet.'); expect(nocturn1?.text.text.la).toBe('V. Ex Sion spécies decóris ejus.\nR. Deus noster maniféste véniet.');
expect(nocturn2?.text.text.la).toBe('V. Emítte Agnum, Dómine, Dominatórem terræ.\nR. De Petra desérti ad montem fíliæ Sion.'); expect(nocturn2?.text.text.la).toBe('V. Emítte Agnum, Dómine, Dominatórem terræ.\nR. De Petra desérti ad montem fíliæ Sion.');
expect(nocturn3?.text.text.la).toBe('V. Egrediétur Dóminus de loco sancto suo.\nR. Véniet ut salvet pópulum suum.'); expect(nocturn3?.text.text.la).toBe('V. Egrediétur Dóminus de loco sancto suo.\nR. Véniet ut salvet pópulum suum.');
@@ -305,7 +307,7 @@ describe('resolveOrdo("matins", ...) Paschaltide Sunday Nocturns I-III seasonal
); );
const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[]; const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[];
const [, nocturn1, nocturn2, nocturn3] = versicles; const [, , nocturn1, nocturn2, nocturn3] = versicles;
expect(nocturn1?.text.text.la).toBe('V. Surréxit Dóminus de sepúlcro, allelúja.\nR. Qui pro nobis pepéndit in ligno, allelúja.'); expect(nocturn1?.text.text.la).toBe('V. Surréxit Dóminus de sepúlcro, allelúja.\nR. Qui pro nobis pepéndit in ligno, allelúja.');
expect(nocturn2?.text.text.la).toBe('V. Surréxit Dóminus vere, allelúja.\nR. Et appáruit Simóni, allelúja.'); expect(nocturn2?.text.text.la).toBe('V. Surréxit Dóminus vere, allelúja.\nR. Et appáruit Simóni, allelúja.');
expect(nocturn3?.text.text.la).toBe('V. Gavísi sunt discípuli, allelúja.\nR. Viso Dómino, allelúja.'); expect(nocturn3?.text.text.la).toBe('V. Gavísi sunt discípuli, allelúja.\nR. Viso Dómino, allelúja.');
@@ -351,7 +353,7 @@ describe('resolveOrdo("matins", ...) Sunday within the Octave of Ascension (2026
); );
const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[]; const versicles = ordo.parts.filter((p) => p.kind === 'versicle') as { text: { text: Record<string, string> } }[];
const [, nocturn1, nocturn2, nocturn3] = versicles; const [, , nocturn1, nocturn2, nocturn3] = versicles;
expect(nocturn1?.text.text.la).toBe('V. Ascéndit Deus in jubilatióne, allelúja.\nR. Et Dóminus in voce tubæ, allelúja.'); expect(nocturn1?.text.text.la).toBe('V. Ascéndit Deus in jubilatióne, allelúja.\nR. Et Dóminus in voce tubæ, allelúja.');
expect(nocturn2?.text.text.la).toBe('V. Ascéndens Christus in altum, allelúja.\nR. Captívam duxit captivitátem, allelúja.'); expect(nocturn2?.text.text.la).toBe('V. Ascéndens Christus in altum, allelúja.\nR. Captívam duxit captivitátem, allelúja.');
expect(nocturn3?.text.text.la).toBe('V. Ascéndo ad Patrem meum, et Patrem vestrum, allelúja.\nR. Deum meum, et Deum vestrum, allelúja.'); expect(nocturn3?.text.text.la).toBe('V. Ascéndo ad Patrem meum, et Patrem vestrum, allelúja.\nR. Deum meum, et Deum vestrum, allelúja.');
@@ -596,7 +598,8 @@ describe('resolveOrdo("matins", ...) Sacred Triduum', () => {
it("leaves an ordinary day's opening block untouched", () => { it("leaves an ordinary day's opening block untouched", () => {
const ordo = resolveOrdo('matins', '2026-08-20'); const ordo = resolveOrdo('matins', '2026-08-20');
expect(ordo.parts[0]?.kind).toBe('versicle'); expect(ordo.parts[0]?.kind).toBe('versicle');
expect(ordo.parts[1]).toMatchObject({ kind: 'psalm', psalmNumber: 3 }); expect(ordo.parts[1]?.kind).toBe('versicle');
expect(ordo.parts[2]).toMatchObject({ kind: 'psalm', psalmNumber: 3 });
}); });
}); });