Compare commits
2 Commits
b90789cab3
...
2a98386bdd
| Author | SHA1 | Date | |
|---|---|---|---|
| 2a98386bdd | |||
| 58b201dc23 |
@@ -19,9 +19,8 @@ across every hour and content type in this app.
|
||||
|
||||
1. **Mechanism gaps** — a real design/code piece not built yet, blocking any content pass on
|
||||
it from starting:
|
||||
- Paschaltide should substitute the ordinary suffrages/ferial-Preces set with a single
|
||||
alleluia-form "Suffragium Paschale" — not modeled; the ordinary set is shown unchanged
|
||||
throughout Paschaltide instead.
|
||||
- (none currently open — the last one, Paschaltide's "Suffragium Paschale" substitution,
|
||||
was closed 2026-09-04, see the dated log below)
|
||||
|
||||
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
|
||||
@@ -5643,3 +5642,44 @@ word-swap, confirmed live), shared "Ángelis suis" versicle. `lauds-hymn-lent.ym
|
||||
checking `lauds-hymn-saturday.yml`'s real content against the same 2026-02-28 Lenten Ember Saturday
|
||||
date) — byte-identical, just needed the status flipped. All 8 files now `verified`; no more draft
|
||||
Lent content anywhere in this app. `npm test` (2025 passed) and `tsc --noEmit` both pass.
|
||||
|
||||
### Paschaltide's "Suffragium Paschale" mechanism (2026-09-04)
|
||||
|
||||
Closed the highest-priority remaining mechanism gap. Live-verified against Divinum Officium (both
|
||||
Monastic Tridentinum 1617 and Tridentine 1906, byte-identical between the two tracks — the source's
|
||||
own `[Suffragium]` macro literally has a `(sed tempore paschali) @:Suffragium Paschale` override,
|
||||
2026-04-20, a plain Eastertide feria): throughout the whole Paschaltide window (`eastertide`/
|
||||
`ascensiontide`/`pentecost` — the same boundary `PASCHALTIDE_SEASONS` already governs elsewhere in
|
||||
this store), two things happen whenever they'd otherwise show at all:
|
||||
|
||||
1. The ordinary 5-suffrage set (Cross/BVM/Joseph/Apostles/Peace) collapses into one single
|
||||
alleluia-form "Suffragium Paschale" block — one antiphon (different at Lauds, "Crucifíxus
|
||||
surréxit a mórtuis...", vs. Vespers, "Crucem sanctam súbiit...", unlike the ordinary 4/5
|
||||
suffrages, which share identical text at both hours), one shared versicle, one shared collect.
|
||||
2. The ferial-Preces litany (`lauds-preces-feriales`/`vespers-preces-feriales`, sourced from
|
||||
Tridentine 1906/1910 since Monastic 1617 has none at all — see that file's own header) drops
|
||||
entirely rather than being replaced by anything ("Preces Feriales{omittitur}" live) — a
|
||||
Sunday/feast's own short litany (`lauds-short-litany`) is untouched, a separate, universal
|
||||
collect-opening dialogue unrelated to this ferial-specific one.
|
||||
|
||||
Exported a new `isPaschaltide(season)` helper from `hours/resolve-common.ts` (wraps the existing
|
||||
`PASCHALTIDE_SEASONS` set, previously private to that file) and used it in both
|
||||
`resolveSuffrages` (gated after the pre-existing "omit suffrages entirely" checks — Double+/active
|
||||
octave/Advent-Christmastide-Passiontide already drop suffrages regardless of season, unaffected)
|
||||
and a new check in `hours/lauds.ts`'s/`hours/vespers.ts`'s own `'lauds-preces'`/`'vespers-preces'`
|
||||
cases (gated on `isFerialOrVigil(day)`, matching the existing predicate that already selects the
|
||||
ferial litany in the first place). `resolveSuffrages` gained a third `hourId: 'lauds' | 'vespers'`
|
||||
parameter (both call sites updated) to pick the right antiphon.
|
||||
|
||||
Authored `lauds-suffrage-paschale.yml` and `vespers-suffrage-paschale.yml` — English on the Vespers
|
||||
antiphon is this project's own translation and left `draft` (the reference engine's own English
|
||||
render leaves that one antiphon untranslated, Latin-only); everything else `verified`.
|
||||
|
||||
Verified end-to-end via `resolveOrdo` on real dates for Lauds (both the suffrage collapse and the
|
||||
Preces omission fire together correctly on a clean Eastertide feria, 2026-04-20) and via a direct
|
||||
`resolveSuffrages` unit call plus a separately-found clean Vespers evening (2026-04-15, since this
|
||||
particular stretch of Eastertide 2026 is otherwise densely packed with First-Vespers anticipations
|
||||
and octaves — Easter's own, the Patronage of St. Joseph's, Ascension's, Pentecost's — that already
|
||||
correctly suppress suffrages for other, pre-existing reasons and would have made a false negative
|
||||
look like a false positive). `npm test` (2025 passed, no pre-existing tests exercised this path at
|
||||
all) and `tsc --noEmit` both pass.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Throughout Paschaltide (Eastertide/Ascensiontide/Pentecost), the whole
|
||||
# ordinary 5-suffrage set (Cross/BVM/Joseph/Apostles/Peace) collapses into
|
||||
# this single alleluia-form "Suffragium Paschale" instead — live-verified
|
||||
# against Divinum Officium (Monastic Tridentinum 1617 and Tridentine 1906,
|
||||
# byte-identical between the two tracks), Lauds live query, 2026-04-20 (a
|
||||
# plain Eastertide feria). Distinct antiphon from Vespers' own
|
||||
# (vespers-suffrage-paschale.yml, "Crucem sanctam súbiit..."); the
|
||||
# versicle/response and collect are shared between both hours.
|
||||
id: lauds-suffrage-paschale
|
||||
text:
|
||||
la: |
|
||||
Ant. Crucifíxus surréxit a mórtuis, et redémit nos, allelúja, allelúja.
|
||||
V. Dícite in natiónibus, allelúja.
|
||||
R. Quia Dóminus regnávit a ligno, allelúja.
|
||||
Orémus.
|
||||
Deus qui pro nobis Fílium tuum Crucis patíbulum subíre voluísti, ut inimíci a nobis expélleres potestátem: concéde nobis fámulis tuis; ut resurrectiónis grátiam consequámur.
|
||||
Per eúmdem Dóminum nostrum Jesum Christum Fílium tuum, qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum.
|
||||
R. Amen.
|
||||
en: |
|
||||
Ant. He that was crucified is risen from the dead, and hath redeemed us. Alleluia, alleluia.
|
||||
V. Say among the heathen, alleluia.
|
||||
R. That the Lord reigneth from the tree, alleluia.
|
||||
Let us pray.
|
||||
O God, who didst send thy Son to suffer death for us upon the Cross, that thou mightest deliver us from the power of the enemy: grant unto us thy servants to be made partakers of his Resurrection.
|
||||
Through the same Jesus Christ, thy Son, Our Lord, Who liveth and reigneth with thee in the unity of the Holy Ghost, God, world without end.
|
||||
R. Amen.
|
||||
status:
|
||||
la: verified
|
||||
en: verified
|
||||
@@ -0,0 +1,30 @@
|
||||
# Vespers' own antiphon for the same "Suffragium Paschale" substitution
|
||||
# described in lauds-suffrage-paschale.yml's own header — shares that
|
||||
# file's versicle/response and collect, but its own distinct antiphon
|
||||
# ("Crucem sanctam súbiit..."), live-verified against Divinum Officium
|
||||
# (Monastic Tridentinum 1617), Vespers live query, 2026-04-20 (a plain
|
||||
# Eastertide feria). English antiphon translation is this project's own
|
||||
# (the reference engine's own English-language render leaves this
|
||||
# particular antiphon untranslated, Latin-only) — status left `draft`
|
||||
# for the English text specifically pending a better-sourced translation.
|
||||
id: vespers-suffrage-paschale
|
||||
text:
|
||||
la: |
|
||||
Ant. Crucem sanctam súbiit, qui inférnum confrégit; accínctus est poténtia, surréxit die tértia, allelúja.
|
||||
V. Dícite in natiónibus, allelúja.
|
||||
R. Quia Dóminus regnávit a ligno, allelúja.
|
||||
Orémus.
|
||||
Deus qui pro nobis Fílium tuum Crucis patíbulum subíre voluísti, ut inimíci a nobis expélleres potestátem: concéde nobis fámulis tuis; ut resurrectiónis grátiam consequámur.
|
||||
Per eúmdem Dóminum nostrum Jesum Christum Fílium tuum, qui tecum vivit et regnat in unitáte Spíritus Sancti, Deus, per ómnia sǽcula sæculórum.
|
||||
R. Amen.
|
||||
en: |
|
||||
Ant. He bore the holy Cross, who broke the gates of hell; he was girded with power, and rose again on the third day, alleluia.
|
||||
V. Say among the heathen, alleluia.
|
||||
R. That the Lord reigneth from the tree, alleluia.
|
||||
Let us pray.
|
||||
O God, who didst send thy Son to suffer death for us upon the Cross, that thou mightest deliver us from the power of the enemy: grant unto us thy servants to be made partakers of his Resurrection.
|
||||
Through the same Jesus Christ, thy Son, Our Lord, Who liveth and reigneth with thee in the unity of the Holy Ghost, God, world without end.
|
||||
R. Amen.
|
||||
status:
|
||||
la: verified
|
||||
en: draft
|
||||
+11
-1
@@ -26,6 +26,7 @@ import {
|
||||
resolveResponsory,
|
||||
resolveOfficeBundle,
|
||||
resolveSuffrages,
|
||||
isPaschaltide,
|
||||
} from './resolve-common';
|
||||
import laudsDefinitionData from '../data/hours/lauds.yml';
|
||||
import laudsAntiphonsData from '../data/hours/lauds-antiphons.yml';
|
||||
@@ -366,7 +367,7 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
|
||||
case 'day-collects':
|
||||
return getDayCollects(day);
|
||||
case 'suffrages':
|
||||
return resolveSuffrages(day, part.omitOnDouble);
|
||||
return resolveSuffrages(day, part.omitOnDouble, 'lauds');
|
||||
case 'versicle':
|
||||
case 'chapter':
|
||||
case 'responsory':
|
||||
@@ -377,6 +378,15 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
|
||||
return [{ kind: 'preces', text: resolveCommon(id), label: getMarianAntiphonLabel(id) }];
|
||||
}
|
||||
case 'lauds-preces': {
|
||||
// Throughout Paschaltide, the whole ferial-Preces litany drops
|
||||
// entirely rather than being replaced by anything — live-verified
|
||||
// ("Preces Feriales{omittitur}" against both Monastic Tridentinum
|
||||
// 1617 and Tridentine 1906, a plain Eastertide feria, 2026-04-20).
|
||||
// Sunday/feast's own short litany is untouched — that's a separate,
|
||||
// universal collect-opening dialogue, not this ferial-specific one.
|
||||
if (isFerialOrVigil(day) && isPaschaltide(day.season)) {
|
||||
return [];
|
||||
}
|
||||
const id = isFerialOrVigil(day) ? 'lauds-preces-feriales' : 'lauds-short-litany';
|
||||
return [{ kind: 'preces', text: resolveCommon(id) }];
|
||||
}
|
||||
|
||||
@@ -306,6 +306,15 @@ export function getMinorHourOverrideId(day: LiturgicalDay): string | undefined {
|
||||
*/
|
||||
const PASCHALTIDE_SEASONS = new Set(['eastertide', 'ascensiontide', 'pentecost']);
|
||||
|
||||
/** Whether `season` falls within the same broad Paschaltide window
|
||||
* `PASCHALTIDE_SEASONS` already governs elsewhere in this file (Marian
|
||||
* antiphon, Common-category text, hymn doxology) — exported so
|
||||
* hours/lauds.ts's and hours/vespers.ts's own ferial-Preces omission can
|
||||
* share the identical boundary rather than redeclaring it. */
|
||||
export function isPaschaltide(season: string): boolean {
|
||||
return PASCHALTIDE_SEASONS.has(season);
|
||||
}
|
||||
|
||||
/**
|
||||
* Which seasonal office-content suffix (if any) a day's season maps to —
|
||||
* shared by Lauds' and Vespers' own resolveOffice, both of which fall
|
||||
@@ -789,7 +798,11 @@ const SUFFRAGE_LABELS: Record<string, string> = {
|
||||
* the caveat on what real practice also suppresses them for that isn't
|
||||
* modeled.
|
||||
*/
|
||||
export function resolveSuffrages(day: LiturgicalDay, omitOnDouble: boolean | undefined): ResolvedPart[] {
|
||||
export function resolveSuffrages(
|
||||
day: LiturgicalDay,
|
||||
omitOnDouble: boolean | undefined,
|
||||
hourId: 'lauds' | 'vespers' = 'lauds',
|
||||
): ResolvedPart[] {
|
||||
// isDoubleOrHigher only ever looks at a sanctoral rank — Christ the
|
||||
// King is modeled as a named temporal winner (see
|
||||
// ALWAYS_OVERRIDE_TEMPORAL_IDS above) with no FeastClass to check at
|
||||
@@ -812,6 +825,18 @@ export function resolveSuffrages(day: LiturgicalDay, omitOnDouble: boolean | und
|
||||
if (omitOnDouble && (isDoubleOrHigher(day.winner) || isChristTheKing || isSeasonallyExcluded || isWithinAnOctave)) {
|
||||
return [];
|
||||
}
|
||||
// Throughout the rest of Paschaltide, the whole ordinary 5-suffrage set
|
||||
// below collapses into a single alleluia-form "Suffragium Paschale" —
|
||||
// live-verified against both Monastic Tridentinum 1617 and Tridentine
|
||||
// 1906 directly (a plain Eastertide feria, 2026-04-20), byte-identical
|
||||
// between the two tracks. Checked after the omit-entirely gate above
|
||||
// (an active octave/Double+/Advent-Christmastide-Passiontide already
|
||||
// drops suffrages regardless of season, unaffected by this) but before
|
||||
// the ordinary per-suffrage filtering below, since this replaces that
|
||||
// filtering outright rather than adjusting it.
|
||||
if (isPaschaltide(day.season)) {
|
||||
return [{ kind: 'preces', text: resolveCommon(`${hourId}-suffrage-paschale`) }];
|
||||
}
|
||||
// "Of the Holy Cross" is the real *ferial*-office suffrage, sourced
|
||||
// from Tridentine 1906/1910 (a different track than the other four,
|
||||
// which come from Monastic 1617 -- that track has no Cross suffrage
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
resolveResponsory,
|
||||
resolveOfficeBundle,
|
||||
resolveSuffrages,
|
||||
isPaschaltide,
|
||||
} from './resolve-common';
|
||||
import vespersDefinitionData from '../data/hours/vespers.yml';
|
||||
import vespersAntiphonsData from '../data/hours/vespers-antiphons.yml';
|
||||
@@ -275,13 +276,19 @@ function resolvePart(part: HourPart, day: LiturgicalDay, weekday: Weekday): Reso
|
||||
];
|
||||
}
|
||||
case 'vespers-preces': {
|
||||
// Throughout Paschaltide, the whole ferial-Preces litany drops
|
||||
// entirely rather than being replaced by anything — see lauds.ts's
|
||||
// identical 'lauds-preces' case for the live-verification detail.
|
||||
if (isFerialOrVigil(day) && isPaschaltide(day.season)) {
|
||||
return [];
|
||||
}
|
||||
const id = isFerialOrVigil(day) ? 'vespers-preces-feriales' : 'lauds-short-litany';
|
||||
return [{ kind: 'preces', text: resolveCommon(id) }];
|
||||
}
|
||||
case 'day-collects':
|
||||
return getDayCollects(day);
|
||||
case 'suffrages':
|
||||
return resolveSuffrages(day, part.omitOnDouble);
|
||||
return resolveSuffrages(day, part.omitOnDouble, 'vespers');
|
||||
case 'preces':
|
||||
return [{ kind: 'preces', text: resolveCommon(part.textRef.id), label: part.label }];
|
||||
case 'versicle':
|
||||
|
||||
Reference in New Issue
Block a user