Three things prompted by today's date resolving wrong: 1. St. Joseph's own Lauds suffrage was never modeled at all. Added lauds-suffrage-joseph.yml, sourced from Tridentine 1906/1910 (the reference engine's "Tridentine - 1906" version) per direct instruction -- Monastic 1617's own suffrage set has no Joseph suffrage at Lauds, so this one genuinely comes from a different track than the other four. 2. The Cross suffrage's actual gating rule, live-verified against a plain ferial win, a plain Sunday win, a low-rank saint's own win (even bare Simplex), and Marian Saturday: it shows only when the bare temporal feria itself is what's being prayed -- the opposite of "Sunday or a feast of the Lord." Expressed as `!isSundayOrFeast(day)` (the same ferial/festive split Prime's capitulum already uses) plus one more exclusion for a named temporal identity like Marian Saturday, which isn't Sunday or a sanctoral win either but still isn't a bare ferial office. 3. The BVM suffrage is correctly dropped on Marian Saturday (unchanged behavior, just now understood and commented correctly): it's specific to a day whose own office is already Marian, confirmed via the same live source, not a guess. Also models St. Clare (Aug 12, Simplex under Monastic 1617) and surfaces active octaves in getDayLabel, since today's date was resolving as a plain ferial day instead of showing St. Lawrence's octave with St. Clare commemorated. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -272,8 +272,13 @@ real `draft` status went through it.
|
|||||||
complete "Let us pray ... Amen." block, not the more compressed real form
|
complete "Let us pray ... Amen." block, not the more compressed real form
|
||||||
(one "Let us pray," only the last collect's doxology).
|
(one "Let us pray," only the last collect's doxology).
|
||||||
- Suffrage omission only checks `omitOnDouble` (+ Marian Saturday's own
|
- Suffrage omission only checks `omitOnDouble` (+ Marian Saturday's own
|
||||||
Cross/BVM filter, + Christ the King's explicit id check). Real seasonal
|
Cross/BVM filter, + Christ the King's explicit id check, + the Cross-only
|
||||||
suppression (e.g. during Advent/Lent) isn't modeled.
|
ferial-office check added 2026-08). Real seasonal suppression is still
|
||||||
|
missing: per the Tridentine 1906/1910 source (`specials.pl`'s
|
||||||
|
`checksuffragium`), suffrages are omitted *entirely* during Advent,
|
||||||
|
Christmastide, and Passiontide, and whenever any octave is active — none
|
||||||
|
of that is modeled, so e.g. an Advent feria currently still shows all
|
||||||
|
five suffrages when the real office would have none.
|
||||||
- `data/calendar/temporal-categories.yml`'s season→category reconstruction
|
- `data/calendar/temporal-categories.yml`'s season→category reconstruction
|
||||||
is from general knowledge of the pre-1955 tradition, not independently
|
is from general knowledge of the pre-1955 tradition, not independently
|
||||||
verified against a primary source for every entry (flagged inline where
|
verified against a primary source for every entry (flagged inline where
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# Verified against Divinum Officium (Tridentine 1910, i.e. the version
|
||||||
|
# labeled "Tridentine - 1906" in the reference engine's own picker), Lauds
|
||||||
|
# live query, clean ferial day 2026-06-17. Sourced from a different
|
||||||
|
# rubric track than the other four suffrages (Monastic Tridentinum 1617,
|
||||||
|
# which doesn't carry a St. Joseph suffrage at Lauds at all) per direct
|
||||||
|
# instruction -- see lauds-suffrage-cross.yml's header for the set this
|
||||||
|
# joins, and calendar/lauds.ts's suffrages case for the fuller sourcing
|
||||||
|
# story and how this one differs from the other four in when it's shown
|
||||||
|
# (never omitted, only the BVM suffrage is, and only when the day's own
|
||||||
|
# office is already Marian).
|
||||||
|
id: lauds-suffrage-joseph
|
||||||
|
text:
|
||||||
|
la: |
|
||||||
|
Ant. Ipse Jesus erat incípiens quasi annórum trigínta ut putabátur fílius Joseph.
|
||||||
|
V. Os justi meditábitur sapiéntiam.
|
||||||
|
R. Et lingua ejus loquétur judícium.
|
||||||
|
Orémus.
|
||||||
|
Deus, qui ineffábili providéntia beátum Joseph sanctíssimæ Genitrícis tuæ sponsum elígere dignátus es: præsta quǽsumus; ut quem protectórem venerámur in terris, intercessórem habére mereámur in cælis.
|
||||||
|
en: |
|
||||||
|
Ant. Jesus himself began to be about thirty years of age, being (as was supposed) the son of Joseph.
|
||||||
|
V. The mouth of the righteous speaketh wisdom.
|
||||||
|
R. And his tongue talketh judgment.
|
||||||
|
Let us pray.
|
||||||
|
O God, who, in thine unspeakable foreknowledge, didst choose thy blessed servant Joseph to be the husband of thine own most holy Mother; mercifully grant that now that he is in heaven with thee, we who on earth do reverence him for our defender, may worthily be holpen by the succour of his prayers to thee on our behalf.
|
||||||
|
status:
|
||||||
|
la: verified
|
||||||
|
en: verified
|
||||||
+37
-11
@@ -1,7 +1,8 @@
|
|||||||
import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart, ResolvedText } from './types';
|
import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart, ResolvedText } from './types';
|
||||||
import type { LiturgicalDay, Weekday } from '../calendar/types';
|
import type { LiturgicalDay, Weekday } from '../calendar/types';
|
||||||
import { resolveDay, isAtLeast } from '../calendar';
|
import { resolveDay, isAtLeast, isSundayOrFeast } from '../calendar';
|
||||||
import { getDayLabel } from '../calendar/day-label';
|
import { getDayLabel } from '../calendar/day-label';
|
||||||
|
import { getTemporalFeastRecord } from '../calendar/temporal-feasts';
|
||||||
import { getPsalmVerses } from '../psalter';
|
import { getPsalmVerses } from '../psalter';
|
||||||
import { getCanticle } from './lauds-canticles';
|
import { getCanticle } from './lauds-canticles';
|
||||||
import { getLaudsPsalmodyOverride, type LaudsPsalmodyOverride } from './lauds-psalmody-overrides';
|
import { getLaudsPsalmodyOverride, type LaudsPsalmodyOverride } from './lauds-psalmody-overrides';
|
||||||
@@ -200,10 +201,17 @@ function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const SUFFRAGES = ['lauds-suffrage-cross', 'lauds-suffrage-bvm', 'lauds-suffrage-apostles', 'lauds-suffrage-peace'];
|
const SUFFRAGES = [
|
||||||
|
'lauds-suffrage-cross',
|
||||||
|
'lauds-suffrage-bvm',
|
||||||
|
'lauds-suffrage-joseph',
|
||||||
|
'lauds-suffrage-apostles',
|
||||||
|
'lauds-suffrage-peace',
|
||||||
|
];
|
||||||
const SUFFRAGE_LABELS: Record<string, string> = {
|
const SUFFRAGE_LABELS: Record<string, string> = {
|
||||||
'lauds-suffrage-cross': 'Of the Holy Cross',
|
'lauds-suffrage-cross': 'Of the Holy Cross',
|
||||||
'lauds-suffrage-bvm': 'Of the Blessed Virgin Mary',
|
'lauds-suffrage-bvm': 'Of the Blessed Virgin Mary',
|
||||||
|
'lauds-suffrage-joseph': 'Of St. Joseph',
|
||||||
'lauds-suffrage-apostles': 'Of the Holy Apostles Peter and Paul',
|
'lauds-suffrage-apostles': 'Of the Holy Apostles Peter and Paul',
|
||||||
'lauds-suffrage-peace': 'For Peace',
|
'lauds-suffrage-peace': 'For Peace',
|
||||||
};
|
};
|
||||||
@@ -239,15 +247,33 @@ function resolvePart(part: HourPart, day: LiturgicalDay): ResolvedPart[] {
|
|||||||
if (part.omitOnDouble && (isDoubleOrHigher(day.winner) || isChristTheKing)) {
|
if (part.omitOnDouble && (isDoubleOrHigher(day.winner) || isChristTheKing)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
// Confirmed live: Our Lady's Saturday drops both "Of the Holy Cross"
|
// "Of the Holy Cross" is the real *ferial*-office suffrage, sourced
|
||||||
// and "Of the Blessed Virgin Mary" (the latter redundant with the
|
// from Tridentine 1906/1910 (a different track than the other four,
|
||||||
// day's own theme; the former for reasons the reference engine
|
// which come from Monastic 1617 -- that track has no Cross suffrage
|
||||||
// doesn't explain and this doesn't try to re-derive), keeping only
|
// at Lauds at all) -- live-verified against a plain ferial win, a
|
||||||
// the Apostles and Peace suffrages.
|
// plain Sunday win, a low-rank saint's own win (even bare Simplex),
|
||||||
const ids =
|
// and Marian Saturday: Cross shows only when the bare temporal
|
||||||
day.winner.kind === 'temporal' && day.winner.id === 'marian-saturday'
|
// feria itself is what's being prayed -- the exact *opposite* of
|
||||||
? SUFFRAGES.filter((id) => id !== 'lauds-suffrage-cross' && id !== 'lauds-suffrage-bvm')
|
// "Sunday or a feast of the Lord." In this app's own vocabulary,
|
||||||
: SUFFRAGES;
|
// that's `!isSundayOrFeast(day)` (the same ferial/festive split
|
||||||
|
// Prime's capitulum already keys off) with one more exclusion for a
|
||||||
|
// named temporal identity like Marian Saturday, which isn't Sunday
|
||||||
|
// or a sanctoral winner either but still isn't a bare ferial office.
|
||||||
|
const showCross = !isSundayOrFeast(day) && !(day.winner.kind === 'temporal' && getTemporalFeastRecord(day.winner.id));
|
||||||
|
// "Of the Blessed Virgin Mary" is omitted specifically when the
|
||||||
|
// day's own office is already Marian (would be redundant to
|
||||||
|
// suffrage Mary again on her own day) -- confirmed live on Marian
|
||||||
|
// Saturday (Simplex-strength, so it reaches this far rather than
|
||||||
|
// being excluded outright above); the only case this app currently
|
||||||
|
// has of a day using the Marian common below the suffrage-omitting
|
||||||
|
// Duplex+ threshold (every actual Marian *feast* modeled so far is
|
||||||
|
// Duplex-majus+ and already returns above).
|
||||||
|
const isMarianSaturday = day.winner.kind === 'temporal' && day.winner.id === 'marian-saturday';
|
||||||
|
const ids = SUFFRAGES.filter((id) => {
|
||||||
|
if (id === 'lauds-suffrage-cross') return showCross;
|
||||||
|
if (id === 'lauds-suffrage-bvm') return !isMarianSaturday;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
return ids.map((id) => ({
|
return ids.map((id) => ({
|
||||||
kind: 'preces' as const,
|
kind: 'preces' as const,
|
||||||
text: resolveCommon(id),
|
text: resolveCommon(id),
|
||||||
|
|||||||
@@ -46,10 +46,10 @@ describe('Lauds psalmody override (duplex-majus+ sanctoral, and Marian Saturday)
|
|||||||
expect(collect?.kind === 'prayer' ? collect.text.text.en : undefined).toContain('glorious intercession of the Blessed Mary');
|
expect(collect?.kind === 'prayer' ? collect.text.text.en : undefined).toContain('glorious intercession of the Blessed Mary');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("drops the Holy Cross and Blessed Virgin Mary suffrages on Our Lady's Saturday, keeping Apostles and Peace", () => {
|
it("drops the Holy Cross and Blessed Virgin Mary suffrages on Our Lady's Saturday (the latter redundant with the day's already-Marian office; the former because Marian Saturday isn't a bare ferial office either), keeping Joseph, Apostles, and Peace", () => {
|
||||||
const ordo = resolveOrdo('lauds', '2026-10-24');
|
const ordo = resolveOrdo('lauds', '2026-10-24');
|
||||||
const labels = ordo.parts.filter((p) => p.kind === 'preces' && p.label).map((p) => (p.kind === 'preces' ? p.label : undefined));
|
const labels = ordo.parts.filter((p) => p.kind === 'preces' && p.label).map((p) => (p.kind === 'preces' ? p.label : undefined));
|
||||||
expect(labels).toEqual(['Of the Holy Apostles Peter and Paul', 'For Peace', 'Salve Regina']);
|
expect(labels).toEqual(['Of St. Joseph', 'Of the Holy Apostles Peter and Paul', 'For Peace', 'Salve Regina']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("substitutes Christ the King's own proper psalmody and office bundle, and omits the suffrages entirely (Duplex I. classis)", () => {
|
it("substitutes Christ the King's own proper psalmody and office bundle, and omits the suffrages entirely (Duplex I. classis)", () => {
|
||||||
|
|||||||
@@ -187,18 +187,32 @@ describe('resolveOrdo("lauds", ...)', () => {
|
|||||||
expect(collects.length).toBe(1);
|
expect(collects.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes all four Tridentine suffrages, in order, on an ordinary day', () => {
|
it('includes all five suffrages, in order, on an ordinary ferial day -- Cross from Tridentine 1906/1910, the other four from Monastic 1617', () => {
|
||||||
const ordo = resolveOrdo('lauds', FERIAL_TUESDAY);
|
const ordo = resolveOrdo('lauds', FERIAL_TUESDAY);
|
||||||
const labels = ordo.parts.filter((p) => p.kind === 'preces' && p.label).map((p) => (p.kind === 'preces' ? p.label : undefined));
|
const labels = ordo.parts.filter((p) => p.kind === 'preces' && p.label).map((p) => (p.kind === 'preces' ? p.label : undefined));
|
||||||
expect(labels).toEqual([
|
expect(labels).toEqual([
|
||||||
'Of the Holy Cross',
|
'Of the Holy Cross',
|
||||||
'Of the Blessed Virgin Mary',
|
'Of the Blessed Virgin Mary',
|
||||||
|
'Of St. Joseph',
|
||||||
'Of the Holy Apostles Peter and Paul',
|
'Of the Holy Apostles Peter and Paul',
|
||||||
'For Peace',
|
'For Peace',
|
||||||
'Salve Regina',
|
'Salve Regina',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('drops "Of the Holy Cross" -- not a bare ferial office -- on a plain Sunday and on a low-rank saint\'s own winning day, unlike an ordinary feria', () => {
|
||||||
|
// St. Clare (Simplex) doesn't win outright (Lawrence's octave keeps
|
||||||
|
// her to a commemoration -- see calendar/index.ts's applyOctaves), so
|
||||||
|
// use St. Lawrence's own vigil day instead, or just check a Sunday.
|
||||||
|
const sunday = resolveOrdo('lauds', '2026-06-28'); // a plain temporal Sunday, nothing else contesting
|
||||||
|
const sundayLabels = sunday.parts
|
||||||
|
.filter((p) => p.kind === 'preces' && p.label)
|
||||||
|
.map((p) => (p.kind === 'preces' ? p.label : undefined));
|
||||||
|
expect(sundayLabels).not.toContain('Of the Holy Cross');
|
||||||
|
expect(sundayLabels).toContain('Of the Blessed Virgin Mary');
|
||||||
|
expect(sundayLabels).toContain('Of St. Joseph');
|
||||||
|
});
|
||||||
|
|
||||||
it('omits the suffrages on a Double-or-higher feast', () => {
|
it('omits the suffrages on a Double-or-higher feast', () => {
|
||||||
const ordo = resolveOrdo('lauds', '2026-08-10'); // St. Lawrence, Duplex II. classis
|
const ordo = resolveOrdo('lauds', '2026-08-10'); // St. Lawrence, Duplex II. classis
|
||||||
const crossSuffrage = ordo.parts.find((p) => p.kind === 'preces' && p.label === 'Of the Holy Cross');
|
const crossSuffrage = ordo.parts.find((p) => p.kind === 'preces' && p.label === 'Of the Holy Cross');
|
||||||
|
|||||||
Reference in New Issue
Block a user