Add regression tests for the remaining psalmody Common categories
Covers common-of-an-angel (both hours, via Guardian Angels' First Vespers/own day), common-of-a-dedication (Vespers, via its own day), and the common-of-an-evangelist/several-women-martyrs aliases (one date-based test via St. Mark where a real date is reachable, direct unit tests where every carrier saint is below this override's rank threshold or shadowed by an existing per-feast override). Two pre-existing Vespers test dates had to move again for the same reason as the previous session's fix: newly-correct category coverage retroactively changed what a "clean ferial"/"own kept evening" date actually resolves to. 2026-09-28 (anticipates St. Michael's own First Vespers) moved to 2026-10-12; Guardian Angels' own day (Oct 2) moved to Oct 1 (her First Vespers) once tracing resolveEveningDay showed she doesn't keep her own Second Vespers there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AHXJAWVAabCKX1JgmDh4Rn
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { resolveOrdo } from '../../src/hours';
|
||||
import { getLaudsCommonOverride } from '../../src/hours/lauds-psalmody-overrides';
|
||||
|
||||
// Clean ferial dates, one per weekday — see data/psalter-distribution.yml
|
||||
// and src/hours/lauds.ts's own generation-script provenance comments for
|
||||
@@ -361,6 +362,49 @@ describe('resolveOrdo("lauds", ...)', () => {
|
||||
expect(numbers).toEqual([66, 50, 63, 64, 148, 149, 150]);
|
||||
});
|
||||
|
||||
it("uses Common-of-an-Angel's own psalmody (reusing St. Michael's own proper text) on Guardian Angels' own day", () => {
|
||||
// Guardian Angels (Oct 2, Duplex Majus) has no proper text of her own
|
||||
// -- live-verified (2026-08-28) that her real Lauds antiphons are St.
|
||||
// Michael's own, byte-for-byte, which is exactly what this category's
|
||||
// content is (see data/hours/lauds-psalmody-overrides/categories/
|
||||
// common-of-an-angel.yml's own header). Psalm numbers stay the usual
|
||||
// fixed Duplex-majus+ set (92, 99, 62), unlike this Common's Vespers
|
||||
// psalmody, which substitutes "Psalmi Dominica" instead.
|
||||
const ordo = resolveOrdo('lauds', '2026-10-02');
|
||||
const numbers = ordo.parts.filter((p) => p.kind === 'psalm').map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
||||
expect(numbers).toEqual([66, 92, 99, 62, 148, 149, 150]);
|
||||
const secondPsalm = ordo.parts.filter((p) => p.kind === 'psalm')[1];
|
||||
expect(secondPsalm?.kind === 'psalm' ? secondPsalm.antiphon?.text.la : undefined).toContain('Stetit Angelus');
|
||||
});
|
||||
|
||||
it('aliases common-of-an-evangelist onto common-of-an-apostle for Lauds psalmody', () => {
|
||||
// Every Evangelist on this calendar (St. John Apostle, St. Luke, St.
|
||||
// Mark) already has their own per-feast Lauds override authored, so
|
||||
// the Common-category tier can never actually surface via
|
||||
// resolveOrdo/a real date for Lauds specifically (unlike Vespers, see
|
||||
// vespers.test.ts's own St. Mark test) -- test the alias wiring
|
||||
// directly instead. St. Mark's and St. Luke's own reference-engine
|
||||
// rule files both say "ex C1a", and votive=C1a returned byte-identical
|
||||
// Lauds psalmody to plain votive=C1 (2026-08-28).
|
||||
const override = getLaudsCommonOverride('st-mark');
|
||||
expect(override?.id).toBe('common-of-an-apostle');
|
||||
expect(override?.groups.map((g) => g.psalms)).toEqual([[92], [99], [62]]);
|
||||
});
|
||||
|
||||
it('aliases common-of-several-women-martyrs onto common-of-a-holy-woman for Lauds psalmody', () => {
|
||||
// No majus+ saint on this calendar actually carries this Common yet
|
||||
// (Ss. Perpetua and Felicity, the only one, are plain Duplex -- below
|
||||
// this override's threshold), so this can't be exercised via
|
||||
// resolveOrdo/a real date; test the alias wiring directly instead.
|
||||
// Ss. Perpetua and Felicity's own reference-engine file says "vide
|
||||
// C7b", and votive=C7b returned these same groups/canticle/Laudate
|
||||
// antiphons as plain votive=C7 (2026-08-28) -- only the Benedictus
|
||||
// antiphon differs, a separate mechanism from this psalmody table.
|
||||
const override = getLaudsCommonOverride('ss-perpetua-and-felicity');
|
||||
expect(override?.id).toBe('common-of-a-holy-woman');
|
||||
expect(override?.groups.map((g) => g.psalms)).toEqual([[92], [99], [62]]);
|
||||
});
|
||||
|
||||
it("resolves St. Gregory the Great's own proper chapter/hymn, not a Common fallback", () => {
|
||||
// Live-verified against Divinum Officium (Monastic Tridentinum
|
||||
// 1617), 2033-03-12 (clean year). See lauds-capitulum-st-gregory-
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { resolveOrdo } from '../../src/hours';
|
||||
import { getVespersCommonOverride } from '../../src/hours/vespers-psalmody-overrides';
|
||||
|
||||
// Every id with an authored Vespers office override (2026-08 sweep) —
|
||||
// same ids, same clean per-saint dates already established for each
|
||||
@@ -75,14 +76,15 @@ describe('resolveOrdo("vespers", ...)', () => {
|
||||
});
|
||||
|
||||
it('joins Ps 115 and 116 under one shared antiphon on Monday', () => {
|
||||
// Not 2026-08-17: that Monday is actually the closing day of St.
|
||||
// Lawrence's own octave (Aug 10-17, Duplex II. classis) -- now that
|
||||
// Vespers has its own duplex-majus+ psalmody override (2026-08-28),
|
||||
// that evening correctly gets Common-of-a-Martyr's own psalms
|
||||
// instead of the plain ferial Monday set, same as Lauds' own
|
||||
// octave-day override already did. 2026-09-28 is a Monday clear of
|
||||
// any such collision.
|
||||
const ordo = resolveOrdo('vespers', '2026-09-28');
|
||||
// Not 2026-08-17 (the closing day of St. Lawrence's own octave, Aug
|
||||
// 10-17, Duplex II. classis) and not 2026-09-28 either (that Monday
|
||||
// evening anticipates St. Michael's own First Vespers, Sept 29,
|
||||
// Duplex I. classis) -- now that Vespers has its own duplex-majus+
|
||||
// psalmody override (2026-08-28), both evenings correctly pick up a
|
||||
// Common's own psalms instead of the plain ferial Monday set, same as
|
||||
// Lauds' own octave-day override already did. 2026-10-12 is a Monday
|
||||
// clear of any such collision.
|
||||
const ordo = resolveOrdo('vespers', '2026-10-12');
|
||||
const psalmParts = ordo.parts.filter((p) => p.kind === 'psalm');
|
||||
const numbers = psalmParts.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
||||
expect(numbers).toEqual([113, 114, 115, 116, 128]);
|
||||
@@ -155,6 +157,66 @@ describe('resolveOrdo("vespers", ...)', () => {
|
||||
expect(numbers).toEqual([109, 111, 112, 131]);
|
||||
});
|
||||
|
||||
it("uses Common-of-an-Angel's own psalmody (reusing St. Michael's own proper text) on Guardian Angels' First Vespers", () => {
|
||||
// Not Guardian Angels' own day itself (Oct 2, Duplex Majus): she
|
||||
// falls short of keepsOwnSecondVespers's duplex-2-classis+ floor, and
|
||||
// Oct 3 (St. Therese of Lisieux, plain Duplex, below this override's
|
||||
// own threshold) claims First Vespers over her own evening, so Oct 2
|
||||
// itself resolves to the plain ferial Friday default instead. Oct 1
|
||||
// (St. Remigius, Simplex, doesn't keep his own evening either)
|
||||
// anticipates Guardian Angels' own First Vespers instead, which does
|
||||
// carry the override. Live-verified (2026-08-28) that her real
|
||||
// Vespers antiphons are St. Michael's own, byte-for-byte, which is
|
||||
// exactly what this category's content is (see data/hours/
|
||||
// vespers-psalmody-overrides/categories/common-of-an-angel.yml's own
|
||||
// header). Psalm numbers here are "Psalmi Dominica" (109-112), not a
|
||||
// Common-specific set.
|
||||
const ordo = resolveOrdo('vespers', '2026-10-01');
|
||||
const numbers = ordo.parts.filter((p) => p.kind === 'psalm').map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
||||
expect(numbers).toEqual([109, 110, 111, 112]);
|
||||
const firstPsalm = ordo.parts.find((p) => p.kind === 'psalm');
|
||||
expect(firstPsalm?.kind === 'psalm' ? firstPsalm.antiphon?.text.la : undefined).toContain('Stetit Angelus');
|
||||
});
|
||||
|
||||
it("uses Common-of-a-Dedication's own psalmody on the Dedication of the Basilica of the Most Holy Saviour's own day", () => {
|
||||
// Nov 9, Duplex II. classis -- keeps its own evening regardless of
|
||||
// tomorrow (Ss. Tryphon and Companions, Simplex). Live-verified
|
||||
// against Divinum Officium (Monastic Tridentinum 1617, votive=C8),
|
||||
// 2026-08-28 -- genuinely its own scheme, not shared with any other
|
||||
// Common (see the category file's own header).
|
||||
const ordo = resolveOrdo('vespers', '2026-11-09');
|
||||
const numbers = ordo.parts.filter((p) => p.kind === 'psalm').map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
||||
expect(numbers).toEqual([109, 110, 111, 147]);
|
||||
});
|
||||
|
||||
it("uses Common-of-an-Apostle's own psalmody on St. Mark Evangelist's own day, via the common-of-an-evangelist alias", () => {
|
||||
// St. Mark (Apr 25, Duplex II. classis, common: common-of-an-
|
||||
// evangelist) has no per-feast Vespers override authored -- his own
|
||||
// reference-engine rule file says "ex C1a", and votive=C1a returned
|
||||
// byte-identical Lauds/Vespers psalmody to plain votive=C1
|
||||
// (2026-08-28), so common-of-an-evangelist is aliased onto
|
||||
// common-of-an-apostle rather than duplicated (see
|
||||
// data/hours/vespers-psalmody-overrides/categories/
|
||||
// common-of-an-apostle.yml's own header).
|
||||
const ordo = resolveOrdo('vespers', '2026-04-25');
|
||||
const numbers = ordo.parts.filter((p) => p.kind === 'psalm').map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
||||
expect(numbers).toEqual([109, 112, 115, 138]);
|
||||
});
|
||||
|
||||
it('aliases common-of-several-women-martyrs onto common-of-a-holy-woman for Vespers psalmody', () => {
|
||||
// No majus+ saint on this calendar actually carries this Common yet
|
||||
// (Ss. Perpetua and Felicity, the only one, are plain Duplex --
|
||||
// below this override's threshold), so this can't be exercised via
|
||||
// resolveOrdo/a real date; test the alias wiring directly instead.
|
||||
// Ss. Perpetua and Felicity's own reference-engine file says "vide
|
||||
// C7b", and votive=C7b returned these same four psalm numbers/
|
||||
// antiphons as plain votive=C7 (2026-08-28) -- only the Magnificat
|
||||
// antiphon differs, a separate mechanism from this psalmody table.
|
||||
const override = getVespersCommonOverride('ss-perpetua-and-felicity');
|
||||
expect(override?.id).toBe('common-of-a-holy-woman');
|
||||
expect(override?.groups.map((g) => g.psalms)).toEqual([[109], [112], [121], [126]]);
|
||||
});
|
||||
|
||||
it('stays on the plain ferial default for a below-threshold feast (Semiduplex), even on its own kept evening', () => {
|
||||
// 2026-08-08 (Ss. Cyriacus/Largus/Smaragdus, Semiduplex) is below the
|
||||
// duplex-majus+ override threshold -- confirmed live against Divinum
|
||||
|
||||
Reference in New Issue
Block a user