Add Te decet laus to Matins, drop Ps 129/50 from ferial Preces
Deploy / deploy (push) Successful in 1m24s

Matins now sings "Te decet laus" (Psalterium/Common/Prayers.txt's [Te
decet]) immediately after the Te Deum on every 3-nocturn day, matching
Rule of Benedict ch. 11's close of Vigils. New common text
te-decet-laus.yml, wired into both matins.ts branches that render a Te
Deum; absent on ferial days along with it.

Also drops Psalm 129 (De profundis) from the Lauds ferial Preces and
Psalm 50 (Miserere) from the Vespers ferial Preces, per direct
instruction — both were embedded inline in the live-transcribed text.
Updated the affected fixture tests to key off a versicle that survives
the removal instead of the now-absent psalm text.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EWzE3kaSZCs79fPBrrE1aF
This commit is contained in:
2026-08-23 09:03:04 -04:00
parent 0fb3b4c13e
commit 42dd4dc04b
8 changed files with 70 additions and 98 deletions
+19 -17
View File
@@ -32,25 +32,27 @@ across every hour and content type in this app.
needs bilingual voice selection (La/En) worked out, and quality for Latin pronunciation
is an open question. Open, not started — needs its own design pass before content/UI work
begins.
- Matins: "Te decet laus" (the short versicle sung right after the closing Gospel+"Amen",
opening Lauds — Rule of Benedict ch. 13, `data/regula/02-13.yml`) isn't modeled or
displayed anywhere. `post-pentecost-15.yml`'s own header comment already flagged this as
"a known simplification"; the user asked (2026-08-23) for it to actually be shown. Needs a
text/part decided (own `ResolvedPart` kind vs. reusing an existing one like `versicle`)
and where in the Matins ordo it renders (after the Gospel-reading-again-in-full that
currently closes Nocturn 3, before/instead of the existing Benedicamus/Fidelium close —
see memory `vu-matins-closing`). Not started.
- ~~Matins: "Te decet laus"~~ — done (2026-08-23). Added as a new common text
(`data/propers/common/te-decet-laus.yml`, sourced from `Psalterium/Common/Prayers.txt`'s
`[Te decet]` block) rendered as a `versicle` part immediately after the Te Deum on every
3-nocturn day (Sunday or Duplex+), in both `hours/matins.ts` branches that push a Te Deum.
Not modeled: the historical Gospel-read-again-in-full step that live-precedes it (a
pre-existing, separate known simplification — see
`data/propers/nocturn-readings/post-pentecost-15.yml`'s own header comment). Absent on
ferial (1-nocturn) days, same gating as the Te Deum itself. `tests/hours/matins.test.ts`
covers both the Sunday branch's presence/content and the ferial branch's absence.
- ~~Matins nocturn-readings responsory formatting~~ — done (2026-08-23), see "Nocturn-
readings responsory marker fix" below.
- Lauds/Vespers ferial Preces (`data/propers/common/lauds-preces-feriales.yml`,
`vespers-preces-feriales.yml`) each embed a full psalm inline within the Preces text
itself — Psalm 129 (De profundis) at Lauds, Psalm 50 (Miserere) at Vespers, per the
reference engine's own `[Preces feriales Vespera] @:Preces feriales Laudes:s/129/50/`
substitution (see each file's own header comment). User asked (2026-08-23) to remove
both psalms from the Preces. Not started — needs deciding whether to just delete the
psalm block (and its own trailing Gloria Patri line) from each file's `text.la`/`text.en`
wholesale, or whether the surrounding V/R litany needs any adjustment once the psalm's
gone.
- ~~Lauds/Vespers ferial Preces psalms~~ — done (2026-08-23). Psalm 129 (De profundis) and
its own trailing Gloria Patri deleted wholesale from
`data/propers/common/lauds-preces-feriales.yml`'s `text.la`/`text.en`; Psalm 50 (Miserere)
and its own Gloria Patri likewise from `vespers-preces-feriales.yml`. Surrounding V/R
litany needed no adjustment — the psalm block sat between two already-independent V/R
sequences. Both files' header comments updated to flag the drop as deliberate, not a
transcription gap. `tests/hours/lauds.test.ts` and `vespers.test.ts` updated to
distinguish the fuller ferial Preces from the short Sunday/feast litany via a versicle
that survives the psalm's removal ("Ego dixi: Dómine, miserére mei") instead of the now-
absent psalm text.
2. **Minimal-proof-done, bulk content pending** — mechanism is built and trusted (a proof
date/entry already resolves correctly end-to-end); what's left is authoring/importing more
@@ -15,6 +15,10 @@
# conditional markup. The King/nation versicle pair, by contrast, *is*
# rendered live despite the template's own rubric note suggesting
# otherwise -- same live-over-template discipline.
#
# Psalm 129 (De profundis), which the live render embeds between the first
# and second V/R blocks with its own Gloria Patri, is deliberately dropped
# here per direct instruction (2026-08) -- not a transcription gap.
id: lauds-preces-feriales
text:
la: |
@@ -51,18 +55,6 @@ text:
V. Dómine, exáudi oratiónem meam.
R. Et clamor meus ad te véniat.
Psalmus 129.
De profúndis clamávi ad te, Dómine: Dómine, exáudi vocem meam.
Fiant aures tuæ intendéntes, in vocem deprecatiónis meæ.
Si iniquitátes observáveris, Dómine: Dómine, quis sustinébit?
Quia apud te propitiátio est: et propter legem tuam sustínui te, Dómine.
Sustínuit ánima mea in verbo ejus: sperávit ánima mea in Dómino.
A custódia matutína usque ad noctem: speret Israël in Dómino.
Quia apud Dóminum misericórdia: et copiósa apud eum redémptio.
Et ipse rédimet Israël, ex ómnibus iniquitátibus ejus.
V. Glória Patri, et Fílio, et Spirítui Sancto.
R. Sicut erat in princípio, et nunc, et semper, et in sǽcula sæculórum. Amen.
V. Dómine, Deus virtútum, convérte nos.
R. Et osténde fáciem tuam, et salvi érimus.
V. Exsúrge, Christe, ádjuva nos.
@@ -103,18 +95,6 @@ text:
V. O Lord, hear my prayer.
R. And let my cry come unto thee.
Psalm 129.
Out of the depths I have cried to thee, O Lord: Lord, hear my voice.
Let thy ears be attentive to the voice of my supplication.
If thou, O Lord, wilt mark iniquities: Lord, who shall stand it.
For with thee there is merciful forgiveness: and by reason of thy law, I have waited for thee, O Lord.
My soul hath relied on his word: my soul hath hoped in the Lord.
From the morning watch even until night, let Israel hope in the Lord.
Because with the Lord there is mercy: and with him plentiful redemption.
And he shall redeem Israel from all his iniquities.
V. Glory be to the Father, and to the Son, and to the Holy Ghost.
R. As it was in the beginning, is now, and ever shall be, world without end. Amen.
V. Turn us again, O Lord, God of Hosts.
R. Show us thy face, and we shall be whole.
V. Arise, O Christ, and help us.
+17
View File
@@ -0,0 +1,17 @@
# Sourced from Psalterium/Common/Prayers.txt's [Te decet] block. Rule of
# Benedict ch. 11: after the abbot reads the closing Gospel following the
# Te Deum, all reply Amen, then the abbot begins this versicle, closing
# Vigils — sung only on a 3-nocturn day (Sunday or Duplex+), right after
# the Te Deum, same gating as `te-deum` itself. This app doesn't model the
# Gospel-read-again-in-full step that precedes it live (a known
# simplification, see data/propers/nocturn-readings/post-pentecost-15.yml's
# own header comment) — this versicle is added directly after the Te Deum.
id: te-decet-laus
text:
la: |
V. Te decet laus, te decet hymnus: tibi glória Deo Patri, et Fílio, cum Spíritu Sancto in sǽcula sæculórum. Amen.
en: |
V. Thou art worthy of praise, thou art worthy of hymns, to Thee be glory: to God the Father and the Son with the Holy Ghost, world without end. Amen.
status:
la: verified
en: verified
@@ -15,6 +15,11 @@
# `textRef: lauds-conclusio` on a ferial or vigil day -- see hours/
# vespers.ts's 'vespers-preces' case for the exact predicate, mirroring
# hours/lauds.ts's 'lauds-preces' case exactly.
#
# Psalm 50 (Miserere), which the live render embeds between the first and
# second V/R blocks with its own Gloria Patri, is deliberately dropped here
# per direct instruction (2026-08) -- not a transcription gap, same as
# lauds-preces-feriales.yml's own Psalm 129 drop.
id: vespers-preces-feriales
text:
la: |
@@ -51,30 +56,6 @@ text:
V. Dómine, exáudi oratiónem meam.
R. Et clamor meus ad te véniat.
Psalmus 50.
Miserére mei, Deus, secúndum magnam misericórdiam tuam.
Et secúndum multitúdinem miseratiónum tuárum, dele iniquitátem meam.
Ámplius lava me ab iniquitáte mea: et a peccáto meo munda me.
Quóniam iniquitátem meam ego cognósco: et peccátum meum contra me est semper.
Tibi soli peccávi, et malum coram te feci: ut justificéris in sermónibus tuis, et vincas cum judicáris.
Ecce enim, in iniquitátibus concéptus sum: et in peccátis concépit me mater mea.
Ecce enim, veritátem dilexísti: incérta et occúlta sapiéntiæ tuæ manifestásti mihi.
Aspérges me hyssópo, et mundábor: lavábis me, et super nivem dealbábor.
Audítui meo dabis gáudium et lætítiam: et exsultábunt ossa humiliáta.
Avérte fáciem tuam a peccátis meis: et omnes iniquitátes meas dele.
Cor mundum crea in me, Deus: et spíritum rectum ínnova in viscéribus meis.
Ne proícias me a fácie tua: et spíritum sanctum tuum ne áuferas a me.
Redde mihi lætítiam salutáris tui: et spíritu principáli confírma me.
Docébo iníquos vias tuas: et ímpii ad te converténtur.
Líbera me de sanguínibus, Deus, Deus salútis meæ: et exsultábit lingua mea justítiam tuam.
Dómine, lábia mea apéries: et os meum annuntiábit laudem tuam.
Quóniam si voluísses sacrifícium, dedíssem útique: holocáustis non delectáberis.
Sacrifícium Deo spíritus contribulátus: cor contrítum, et humiliátum, Deus, non despícies.
Benígne fac, Dómine, in bona voluntáte tua Sion: ut ædificéntur muri Jerúsalem.
Tunc acceptábis sacrifícium justítiæ, oblatiónes, et holocáusta: tunc impónent super altáre tuum vítulos.
V. Glória Patri, et Fílio, et Spirítui Sancto.
R. Sicut erat in princípio, et nunc, et semper, et in sǽcula sæculórum. Amen.
V. Dómine, Deus virtútum, convérte nos.
R. Et osténde fáciem tuam, et salvi érimus.
V. Exsúrge, Christe, ádjuva nos.
@@ -115,30 +96,6 @@ text:
V. O Lord, hear my prayer.
R. And let my cry come unto thee.
Psalm 50.
Have mercy on me, O God, according to thy great mercy.
And according to the multitude of thy tender mercies blot out my iniquity.
Wash me yet more from my iniquity, and cleanse me from my sin.
For I know my iniquity, and my sin is always before me.
To thee only have I sinned, and have done evil before thee: that thou mayst be justified in thy words, and mayst overcome when thou art judged.
For behold I was conceived in iniquities; and in sins did my mother conceive me.
For behold thou hast loved truth: the uncertain and hidden things of thy wisdom thou hast made manifest to me.
Thou shalt sprinkle me with hyssop, and I shall be cleansed: thou shalt wash me, and I shall be made whiter than snow.
To my hearing thou shalt give joy and gladness: and the bones that have been humbled shall rejoice.
Turn away thy face from my sins, and blot out all my iniquities.
Create a clean heart in me, O God: and renew a right spirit within my bowels.
Cast me not away from thy face; and take not thy holy spirit from me.
Restore unto me the joy of thy salvation, and strengthen me with a perfect spirit.
I will teach the unjust thy ways: and the wicked shall be converted to thee.
Deliver me from blood, O God, thou God of my salvation: and my tongue shall extol thy justice.
O Lord, thou wilt open my lips: and my mouth shall declare thy praise.
For if thou hadst desired sacrifice, I would indeed have given it: with burnt offerings thou wilt not be delighted.
A sacrifice to God is an afflicted spirit: a contrite and humbled heart, O God, thou wilt not despise.
Deal favourably, O Lord, in thy good will with Sion; that the walls of Jerusalem may be built up.
Then shalt thou accept the sacrifice of justice, oblations and whole burnt offerings: then shall they lay calves upon thy altar.
V. Glory be to the Father, and to the Son, and to the Holy Ghost.
R. As it was in the beginning, is now, and ever shall be, world without end. Amen.
V. Turn us again, O Lord, God of Hosts.
R. Show us thy face, and we shall be whole.
V. Arise, O Christ, and help us.
+2
View File
@@ -491,6 +491,7 @@ export function resolveOrdo(date: string): ResolvedOrdo {
parts.push(...sundayCanticleNocturn(sundayAntiphons.nocturn3, day));
parts.push(...(nocturn3Readings ?? []));
parts.push({ kind: 'te-deum', text: resolveCommon('te-deum') });
parts.push({ kind: 'versicle', text: resolveCommon('te-decet-laus') });
} else if (threeNocturns) {
// A Duplex+ weekday feast — genuinely different psalmody from a real
// Sunday's, not the same content reused. getMatinsPsalmodyOverride
@@ -523,6 +524,7 @@ export function resolveOrdo(date: string): ResolvedOrdo {
parts.push(...(nocturn3Readings ?? []));
}
parts.push({ kind: 'te-deum', text: resolveCommon('te-deum') });
parts.push({ kind: 'versicle', text: resolveCommon('te-decet-laus') });
} else {
parts.push(...ferialAntiphonedNocturn(day));
parts.push(...(nocturn1Readings ?? []));
+8 -4
View File
@@ -166,11 +166,15 @@ describe('resolveOrdo("lauds", ...)', () => {
expect(collectIndex).toBeGreaterThan(litanyIndex);
});
it('uses the fuller Tridentine 1906/1910 ferial Preces (with Psalm 129) on a plain ferial day, not the short Sunday/feast litany', () => {
it('uses the fuller Tridentine 1906/1910 ferial Preces on a plain ferial day, not the short Sunday/feast litany', () => {
// Psalm 129 (De profundis), present in the live render, is deliberately
// dropped from this app's own text (2026-08) — 'Ego dixi' is the next
// versicle after where the psalm used to sit, still unique to the
// fuller ferial form vs. the short litany.
const ordo = resolveOrdo('lauds', FERIAL_TUESDAY);
const preces = ordo.parts.find((p) => p.kind === 'preces' && p.text.text.la?.includes('Kýrie, eléison'));
expect(preces?.kind === 'preces' ? preces.text.text.la : undefined).toContain('De profúndis clamávi');
expect(preces?.kind === 'preces' ? preces.text.text.en : undefined).toContain('Out of the depths');
expect(preces?.kind === 'preces' ? preces.text.text.la : undefined).toContain('Ego dixi: Dómine, miserére mei');
expect(preces?.kind === 'preces' ? preces.text.text.en : undefined).toContain('I said: Lord, be merciful');
});
it('uses the short Sunday/feast litany, without Psalm 129, on a Sunday and on a real saint\'s own winning day', () => {
@@ -186,7 +190,7 @@ describe('resolveOrdo("lauds", ...)', () => {
it('still uses the fuller ferial Preces on a Vigil, even though a Vigil is a sanctoral winner (unlike isSundayOrFeast elsewhere)', () => {
const ordo = resolveOrdo('lauds', '2028-08-09'); // Vigil of St. Lawrence wins outright this year (not a Sunday)
const preces = ordo.parts.find((p) => p.kind === 'preces' && p.text.text.la?.includes('Kýrie, eléison'));
expect(preces?.kind === 'preces' ? preces.text.text.la : undefined).toContain('Psalmus 129');
expect(preces?.kind === 'preces' ? preces.text.text.la : undefined).toContain('Ego dixi: Dómine, miserére mei');
});
it('resolves just the winners own collect on a plain day with nothing commemorated', () => {
+8 -2
View File
@@ -41,6 +41,9 @@ describe('resolveOrdo("matins", ...) ferial (1-nocturn) branch', () => {
expect(psalms).toEqual([3, 94, 43, 44, 47, 48, 49, 54, 55, 58, 59]);
expect(ordo.parts.some((p) => p.kind === 'te-deum')).toBe(false);
expect(ordo.parts.some((p) => p.kind === 'canticle')).toBe(false);
// "Te decet laus" is sung only right after the Te Deum on a 3-nocturn
// day (2026-08) — absent here along with the Te Deum itself.
expect(ordo.parts.some((p) => p.kind === 'versicle' && p.text.text.la?.includes('Te decet laus'))).toBe(false);
});
it("gives every nocturn psalm its own antiphon and includes Tuesday's own versicle (data/hours/matins-ferial-antiphons.yml)", () => {
@@ -125,12 +128,15 @@ 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)', () => {
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).
expect(versicles).toHaveLength(4);
// Opening Deus-in-adjutorium versicle + one per nocturn (1, 2, 3) +
// the closing "Te decet laus" versicle after the Te Deum (2026-08).
expect(versicles).toHaveLength(5);
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(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.');
// The 5th versicle is "Te decet laus", right after the Te Deum (2026-08).
expect(versicles[4]?.text.text.la).toContain('Te decet laus');
});
it("resolves the user's own bible-plan reading (Tobit/Sirach) for Nocturn 1", () => {
+7 -3
View File
@@ -229,11 +229,15 @@ describe('resolveOrdo("vespers", ...)', () => {
expect(collectIndex).toBeGreaterThan(litanyIndex);
});
it('uses the fuller Tridentine 1906/1910 ferial Preces (with Psalm 50) on a plain ferial day, not the short Sunday/feast litany', () => {
it('uses the fuller Tridentine 1906/1910 ferial Preces on a plain ferial day, not the short Sunday/feast litany', () => {
// Psalm 50 (Miserere), present in the live render, is deliberately
// dropped from this app's own text (2026-08) — 'Ego dixi' is the next
// versicle after where the psalm used to sit, still unique to the
// fuller ferial form vs. the short litany.
const ordo = resolveOrdo('vespers', '2026-06-16');
const preces = ordo.parts.find((p) => p.kind === 'preces' && p.text.text.la?.includes('Kýrie, eléison'));
expect(preces?.kind === 'preces' ? preces.text.text.la : undefined).toContain('Miserére mei, Deus');
expect(preces?.kind === 'preces' ? preces.text.text.en : undefined).toContain('Have mercy on me, O God');
expect(preces?.kind === 'preces' ? preces.text.text.la : undefined).toContain('Ego dixi: Dómine, miserére mei');
expect(preces?.kind === 'preces' ? preces.text.text.en : undefined).toContain('I said: Lord, be merciful');
});
it("uses the short Sunday/feast litany, without Psalm 50, on a Sunday and on a real saint's own winning day", () => {