Compare commits

...

2 Commits

Author SHA1 Message Date
will c3e87ac57a Record Common-of-Several-Martyrs Matins psalmody work in TODO.md
Deploy / deploy (push) Successful in 1m24s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VpKT73TSqRNnE2CSD8GpUY
2026-08-25 06:41:21 -04:00
will e82f3ac018 Author Common-of-Several-Martyrs Matins psalmody, largest remaining category
Live-verified against Ss. Fabian and Sebastian's clean date (2029-01-20,
Monastic Tridentinum 1617). Genuinely distinct psalm scheme from
common-of-a-martyr (single martyr), not a duplicate. Adds Wisdom 3:1-6
to the scripture store for Nocturn 3's canticles. Swaps the matins.test.ts
ferial-fallback proof to St. Anthony Abbot now that Fabian/Sebastian
resolve through this new category instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VpKT73TSqRNnE2CSD8GpUY
2026-08-25 06:41:18 -04:00
4 changed files with 222 additions and 15 deletions
+44 -5
View File
@@ -84,13 +84,13 @@ across every hour and content type in this app.
`src/data/scripture/` — long-term project, explicitly deferred; Matins scripture
citations resolve to `missing` text until it lands.
- Matins psalmody overrides for a Duplex+ weekday feast (see "Matins psalmody overrides"
below): mechanism refactored to category-keyed (`categories/*.yml` + `saints/*.yml`), four
below): mechanism refactored to category-keyed (`categories/*.yml` + `saints/*.yml`), five
categories authored (Common of a Martyr via St. Lawrence, Common of an Apostle via St.
Andrew, Common of a Confessor via St. Francis of Paola, Common of a Confessor-Bishop via
St. Basil the Great). Every other Common category (Virgin, Doctor, Common of Several
Martyrs, etc. — the largest remaining population) still falls back to the plain ferial
weekday table, redistributed into 3 nocturns, until its own category's real psalmody is
authored.
St. Basil the Great, Common of Several Martyrs — the largest single category by population,
40 saints/groups — via Ss. Fabian and Sebastian). Every other Common category (Virgin,
Doctor, Abbot, etc.) still falls back to the plain ferial weekday table, redistributed into
3 nocturns, until its own category's real psalmody is authored.
- The four "Commemoratio Octavæ" Ant+V/R+collect blocks (Christmas Octave's own
Nativity/Stephen/John/Holy-Innocents commemorations, e.g. on Dec 30) are now done —
see "Octave content" below. St. Frances of Rome's/
@@ -2729,6 +2729,45 @@ textual variants of the same hymn, don't assume a single attached translation wa
whichever variant happens to be nearest it — check the imagery/vocabulary against each Latin
candidate before trusting the pairing.
### Matins psalmody overrides — Common-of-Several-Martyrs authored, largest remaining category (2026-08-25)
Fifth Common category authored for `matins-psalmody-overrides`, same live-verify-a-saint-with-
no-proper-antiphon method as the previous four: **`common-of-several-martyrs`**, from Ss. Fabian
and Sebastian (2029-01-20, Duplex, confirmed clean — a Saturday, no Sunday collision — per their
own saint-file comment). Live-verified (Monastic Tridentinum 1617, `command=prayMatutinum`)
genuinely distinct from `common-of-a-martyr` (single martyr), not a duplicate: Nocturn 1 = Ps
1,2,10,14,15,23 (vs 1,2,4,5,8,10), Nocturn 2 = Ps 32,33,45,60,63,78 (vs 14,20,23,63,64,91), and a
different Nocturn 3 canticle source (Wisdom 3:1-6/3:7-9/10:17-21, one shared "Beáti, qui
persecutiónem patiúntur" antiphon, vs Sirach 14/15 + Jeremiah 17 + Sirach 31). New scripture
verses added: `data/scripture/sap-3.yml` gained 3:1-6 (3:7-9 already existed from St. Andrew's
own canticle); `sap-10.yml`'s existing 10:17-21 reused as-is, no changes needed.
This is the **largest single Common category by population** (40 saints/groups carry this
`common` id per calendar-wide grep, more than `common-of-a-confessor`'s 37 or `common-of-a-
martyr-bishop`'s 35) — authoring it unlocks real, non-ferial-fallback Matins psalmody for all 40
at once. Checked every Duplex+ saint/group in the category (only Holy Innocents and Ss. Fabian
and Sebastian themselves are Duplex+; Holy Innocents already has full proper content of its own,
Fabian/Sebastian has none) — same as every category before it, no saint is currently eligible
for its own `saints/*.yml` entry under the proper-only policy.
**Wrinkle**: the reference engine's own English track has no translation at all for two of this
category's antiphons (Nocturn 1's Ps 10 antiphon and Nocturn 3's "Beáti, qui persecutiónem"
Beatitude antiphon, Matt 5:10) — its rendered English column just repeats the Latin for both.
Original English translations supplied for both (matching this project's existing Douay-adjacent
phrasing elsewhere, e.g. the Rule of Benedict's own "persecution for righteousness" wording) —
flagged inline in the category file's own header comment, not silently passed through as
`verified` without a note, even though the resolver's `verifiedText` helper doesn't distinguish
draft from verified at this granularity (a pre-existing mechanism limitation, not new here).
`tests/hours/matins.test.ts`'s old ferial-fallback proof (Ss. Fabian and Sebastian, now
superseded now that their Common has real content) is rewritten as a Common-tier proof; a fresh
genuine ferial-fallback proof was added instead (St. Anthony, Abbot, `common-of-an-abbot` — still
unauthored — 2029-01-17, confirmed clean). `npm test` (471 tests), `tsc --noEmit` both pass.
**Still open**: Confessor-Not-a-Bishop [6], Confessor-Pope [3], Confessor-Doctor [4], Virgin [11],
Virgin-Martyr [17], Abbot [16], Holy Woman [3], Widow [6], Angel [5], Evangelist [3], and the
smaller one-off Commons — none has a category file yet.
## Known, deliberate simplifications (not bugs — working as designed)
- `getDayCollects`: each collect in a multi-collect day renders as its own
@@ -0,0 +1,111 @@
# Generic Common-of-Several-Martyrs Matins psalmody, live-verified
# against Divinum Officium (Monastic Tridentinum 1617,
# command=prayMatutinum, 2029-01-20 -- Ss. Fabian and Sebastian,
# Martyrs, whose own rule is entirely Common, no proper antiphon of
# their own -- so their own output *is* this category's generic
# scheme). Confirmed genuinely distinct from `common-of-a-martyr.yml`'s
# scheme (a single martyr), not a duplicate: different psalm numbers in
# both nocturns (Nocturn 1: 1,2,10,14,15,23 here vs 1,2,4,5,8,10 there;
# Nocturn 2: 32,33,45,60,63,78 here vs 14,20,23,63,64,91 there) and a
# different Nocturn 3 canticle source (Wisdom 3/10 here vs Sirach 14/15
# + Jeremiah 17 + Sirach 31 there).
#
# One wrinkle: the reference engine's own English track has no
# translation for two antiphons here -- Nocturn 1's Psalm 10 antiphon
# ("Oculi Dómini...") and Nocturn 3's ("Beáti, qui persecutiónem...",
# the standard "Blessed are they that suffer persecution" Beatitude
# text, Matt 5:10) -- its rendered "English" column just repeats the
# Latin for both. The English given below for those two is an original
# translation (matching this project's other Douay-adjacent psalm-
# antiphon phrasing, e.g. Ps 10:5's own "His eyes look on the poor
# man"), not reused reference-engine text.
#
# 40 saints/groups on the calendar carry this `common` id -- the
# largest single Common category by population -- so this file unlocks
# real (non-ferial-fallback) Matins psalmody for all of them at once,
# even before any of them has its own proper `saints/*.yml` entry.
id: common-of-several-martyrs
nocturn1:
groups:
- psalms: [1]
antiphon:
la: "Secus decúrsus aquárum * plantávit víneam justórum, et in lege Dómini fuit volúntas eórum."
en: "By the rivers of water * hath the Lord planted the vineyard of the righteous, and in His Law do they meditate day and night."
- psalms: [2]
antiphon:
la: "Tamquam aurum * in fornáce probávit eléctos Dóminus: et quasi holocáusta accépit eos in ætérnum."
en: "As gold in the furnace * hath the Lord tried His chosen ones, and received them for ever as a burnt-offering."
- psalms: [10]
antiphon:
la: "Oculi Dómini * respexérunt in páuperes, † cum peccatóres arcus suos in eos inténderent."
en: "The eyes of the Lord * looked upon the poor, when the sinners bent their bow against them."
- psalms: [14]
antiphon:
la: "Dabo Sanctis meis * locum nominátum in regno Patris mei, dicit Dóminus."
en: "I will give unto My Saints a place * in the kingdom of My Father, every one by his own name, saith the Lord."
- psalms: [15]
antiphon:
la: "Sanctis, qui in terra sunt ejus, * mirificávit omnes voluntátes meas inter illos."
en: "To the Saints that are in the earth * Thou hast made all my counsels admirable."
- psalms: [23]
antiphon:
la: "Sancti qui sperant in Dómino, * habébunt fortitúdinem, assúment pennas ut áquilæ, volábunt, et non defícient."
en: "The Saints that wait upon the Lord * shall renew their strength; they shall mount up with wings as eagles, they shall fly and not faint."
versicle:
v:
la: "Lætámini in Dómino, et exsultáte justi."
en: "Be glad in the Lord, and rejoice, ye just,"
r:
la: "Et gloriámini omnes recti corde."
en: "And glory, all ye right of heart."
nocturn2:
groups:
- psalms: [32]
antiphon:
la: "Justi autem * in perpétuum vivent, et apud Dóminum est merces eórum."
en: "The righteous live * for evermore; their reward also is with the Lord."
- psalms: [33]
antiphon:
la: "Tradidérunt * córpora sua in mortem, ne servírent idólis: ídeo coronáti póssident palmam."
en: "They gave up their bodies unto death * rather than serve idols and therefore have they crowns on their heads and palms in their hands."
- psalms: [45]
antiphon:
la: "Ecce merces * Sanctórum copiósa est apud Deum: ipsi vero mórtui sunt pro Christo, et vivent in ætérnum."
en: "Behold, how great with God is the reward * of His Saints; yea, they who died for Christ's sake shall live for ever and ever."
- psalms: [60]
antiphon:
la: "Istórum est enim * regnum cælórum, qui contempsérunt vitam mundi, et pervenérunt ad premia regni, et lavérunt stolas suas in sanguine Agni."
en: "For theirs is the Kingdom of heaven * who love not their lives in this world, and have attained unto the reward of the Kingdom, and have washed their robes in the blood of the Lamb."
- psalms: [63]
antiphon:
la: "Sanguis sanctórum mártyrum * pro Christo effúsus est in terra; ideo adépti sunt munera sempitérna."
en: "The blood * of the holy Martyrs was poured for Christ on earth, therefore they have obtained eternal rewards."
- psalms: [78]
antiphon:
la: "Víndica Domine * sánguinem Sanctórum tuórum, qui effúsus est super terram."
en: "Avenge, O Lord, the blood of thy saints, which is shed over the Earth."
versicle:
v:
la: "Exsúltent justi in conspéctu Dei."
en: "Let the righteous rejoice before God."
r:
la: "Et delecténtur in lætítia."
en: "Yea, let them exceedingly rejoice."
nocturn3:
antiphon:
la: "Beáti, * qui persecutiónem patiúntur propter justítiam, quóniam ipsórum est regnum cælórum."
en: "Blessed are they * that suffer persecution for righteousness' sake, for theirs is the kingdom of heaven."
canticles:
- refs:
- { book: sap, chapter: 3, verses: "1-6" }
- refs:
- { book: sap, chapter: 3, verses: "7-9" }
- refs:
- { book: sap, chapter: 10, verses: "17-21" }
versicle:
v:
la: "Justi autem in perpétuum vivent."
en: "The righteous live for evermore."
r:
la: "Et apud Dóminum est merces eórum."
en: "Their reward also is with the Lord."
+35 -3
View File
@@ -1,10 +1,42 @@
# Wisdom 3:7-9, transcribed from a live Divinum Officium query (Monastic
# Tridentinum 1617, command=prayMatutinum, 2026-08-18 -- St. Andrew's own
# day, 2026-11-30, Matins Nocturn III's second canticle). Only these
# Wisdom 3:1-9, transcribed from live Divinum Officium queries (Monastic
# Tridentinum 1617, command=prayMatutinum): verses 7-9 from 2026-08-18 --
# St. Andrew's own day, 2026-11-30, Matins Nocturn III's second canticle;
# verses 1-6 added 2029-01-20 -- Ss. Fabian and Sebastian, Common of
# Several Martyrs, Matins Nocturn III's first canticle. Only these
# verses are authored; the rest of the chapter is unauthored.
book: sap
chapter: 3
verses:
- n: 1
text:
la: "Justórum autem ánimæ in manu Dei sunt, * et non tangent illos torméntum mortis."
en: "But the souls of the just are in the hand of God, and the torment of death shall not touch them."
status: { la: verified, en: verified }
- n: 2
text:
la: "Visi sunt óculis insipiéntium mori, * et æstimáta est afflíctio éxitus illórum,"
en: "In the sight of the unwise they seemed to die: and their departure was taken for misery:"
status: { la: verified, en: verified }
- n: 3
text:
la: "Et quod a nobis est iter extermínium; * illi autem sunt in pace:"
en: "And their going away from us, for utter destruction: but they are in peace."
status: { la: verified, en: verified }
- n: 4
text:
la: "Etsi coram homínibus torménta passi sunt, * spes illórum immortalitáte plena est."
en: "And though in the sight of men they suffered torments, their hope is full of immortality."
status: { la: verified, en: verified }
- n: 5
text:
la: "In paucis vexáti, in multis bene disponéntur, * quóniam Deus tentávit eos, et invénit illos dignos se."
en: "Afflicted in few things, in many they shall be well rewarded: because God hath tried them, and found them worthy of himself."
status: { la: verified, en: verified }
- n: 6
text:
la: "Tamquam aurum in fornáce probávit illos, et quasi holocáusti hóstiam accépit illos, * et in témpore erit respéctus illórum."
en: "As gold in the furnace he hath proved them, and as a victim of a holocaust he hath received them, and in time there shall be respect had to them."
status: { la: verified, en: verified }
- n: 7
text:
la: "Fulgébunt justi, * et tamquam scintíllæ in arundinéto discúrrent."
+32 -7
View File
@@ -286,18 +286,43 @@ describe('resolveOrdo("matins", ...) Duplex+ weekday-feast (3-nocturn, non-Sunda
expect(common.parts.some((p) => p.kind === 'canticle')).toBe(true);
});
it("falls through to Common-of-Several-Martyrs's own generic psalmody -- a genuinely different scheme from the single-martyr Common", () => {
// Ss. Fabian and Sebastian (Duplex, Common of Several Martyrs, no
// proper antiphon of their own) -- 2029-01-20, a Saturday, confirmed
// clean (no Sunday collision) per their own saint-file comment.
const common = resolveOrdo('matins', '2029-01-20');
const psalms = common.parts.filter((p) => p.kind === 'psalm').map((p) => (p as { psalmNumber: number }).psalmNumber);
expect(psalms).toEqual([3, 94, 1, 2, 10, 14, 15, 23, 32, 33, 45, 60, 63, 78]);
expect(common.parts.some((p) => p.kind === 'te-deum')).toBe(true);
expect(common.parts.some((p) => p.kind === 'canticle')).toBe(true);
const psalmParts = common.parts.filter((p) => p.kind === 'psalm') as { psalmNumber: number; antiphon?: { status: Record<string, string> } }[];
const nocturnPsalms = psalmParts.filter((p) => ![3, 94].includes(p.psalmNumber));
for (const p of nocturnPsalms) {
expect(p.antiphon?.status.la).toBe('verified');
expect(p.antiphon?.status.en).toBe('verified');
}
const canticles = common.parts.filter((p) => p.kind === 'canticle') as { canticleId: string; text: { status: Record<string, string> } }[];
expect(canticles).toHaveLength(3);
expect(canticles[0]?.canticleId).toBe('sap-3-1-6');
for (const c of canticles) {
expect(c.text.status.la).toBe('verified');
expect(c.text.status.en).toBe('verified');
}
});
it('falls all the way back to the plain ferial weekday table, redistributed into 3 nocturns, when neither a proper nor a Common entry is authored', () => {
// Ss. Fabian and Sebastian (Duplex, Common of Several Martyrs -- no
// St. Anthony, Abbot (Duplex, Common of an Abbot -- no
// matins-psalmody-overrides category authored yet for either tier)
// -- 2029-01-20, a Saturday, confirmed clean (no Sunday collision)
// per their own saint-file comment.
const fallback = resolveOrdo('matins', '2029-01-20');
// -- 2029-01-17, a Wednesday, confirmed clean (no Sunday collision).
const fallback = resolveOrdo('matins', '2029-01-17');
const psalms = fallback.parts.filter((p) => p.kind === 'psalm').map((p) => (p as { psalmNumber: number }).psalmNumber);
// Ps 3 + 94, then Saturday's own 9-psalm ferial table
// (psalter-distribution.yml), not any Common-of-Several-Martyrs scheme.
// Ps 3 + 94, then Wednesday's own 9-psalm ferial table
// (psalter-distribution.yml), not any Common-of-an-Abbot scheme.
expect(psalms[0]).toBe(3);
expect(psalms[1]).toBe(94);
expect(psalms.slice(2)).toEqual(getPsalmsFor('matins', 'saturday').map((r) => r.number));
expect(psalms.slice(2)).toEqual(getPsalmsFor('matins', 'wednesday').map((r) => r.number));
expect(fallback.parts.some((p) => p.kind === 'te-deum')).toBe(true);
expect(fallback.parts.some((p) => p.kind === 'canticle')).toBe(false);
});