calendar: model Our Lady's Saturday as a real occurrence outcome
Deploy / deploy (push) Successful in 49s
Deploy / deploy (push) Successful in 49s
On a free Saturday (nothing privileged already claims it, no active octave), the day's own identity is now "Our Lady's Saturday" rather than an anonymous ordinary-feria -- mirrors privileged-feria-minor exactly, per direct instruction: Semiduplex-or-higher still wins outright (Marian Saturday doesn't apply at all); below that (Simplex, and Vigil, both under semiduplex on the FeastClass scale) loses and is commemorated instead. Layered additively after decideOccurrence, same shape as applyOctaves -- never touches decideOccurrence's own rules. Needed a real winner identity (not just the plain temporal feria id) so day-label/antiphon/collect sourcing can recognize it -- added a temporal-feasts record purely for that, and taught getDayLabel to check it for any named temporal winner (a small, free improvement for Christmas/Pentecost's own labels too, previously unhandled). hours: build the duplex-majus+ Lauds psalmody override (per-feast) lauds-psalmody no longer unconditionally uses the plain weekday default: a duplex-majus-or-higher sanctoral winner, or Our Lady's Saturday (unconditional, no rank threshold -- it isn't competing with the weekday default the way a saint is), now substitutes its own proper psalm groups/antiphons/canticle. Per-feast, not per-Common, per direct instruction, even though most duplex-majus+ saints across the year don't have one authored yet and fall back to the plain weekday default until they do. Content for the worked example (St. Lawrence's own day) surfaced a real bug while sourcing it: st-lawrence-antiphon.yml had been read from the Roman/secular rite's own [Ant 1], not Monastic 1617's actual Benedictus antiphon for that day -- corrected from a fresh live query. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -101,10 +101,56 @@ export function resolveDay(isoDate: string): LiturgicalDay {
|
||||
}
|
||||
|
||||
winner = applyOctaves(isoDate, winner, commemorations);
|
||||
winner = applyMarianSaturday(isoDate, weekday, temporalCategory, winner, commemorations);
|
||||
|
||||
return { date: isoDate, weekday, season, temporalCategory, winner, commemorations };
|
||||
}
|
||||
|
||||
/**
|
||||
* Layered on top of everything above, same spirit as applyOctaves: never
|
||||
* changes decideOccurrence's own rules, just relabels the result on a free
|
||||
* Saturday. Real standing of its own (per direct instruction, mirrors
|
||||
* privileged-feria-minor exactly) — a Semiduplex-or-higher saint still
|
||||
* wins outright and this never applies; a Simplex (or Vigil) saint loses
|
||||
* to it and is commemorated instead, same as an Advent feria would demote
|
||||
* one. `ordinary-feria` is the only category this touches — every
|
||||
* privileged season/day (Ember Saturdays, Advent, Lent, ...) already has
|
||||
* its own real standing and keeps it untouched.
|
||||
*
|
||||
* The relabel (not just leaving `winner` as the plain temporal id) is
|
||||
* what lets getDayLabel/getBenedictusAntiphon/getDayCollects/getLaudsPsalmodyOverride
|
||||
* all recognize this day as "Our Lady's Saturday" rather than an
|
||||
* anonymous feria — see data/calendar/temporal-feasts/marian-saturday.yml.
|
||||
*
|
||||
* Also gated on no octave being active: `ordinary-feria` isn't only "a
|
||||
* genuinely free Saturday" — Pentecost's own Ember Saturday is
|
||||
* deliberately classified this way too (see data/calendar/temporal-
|
||||
* categories.yml), specifically so the octave layer above can reach it.
|
||||
* Found via a real regression: without this gate, Pentecost's Ember
|
||||
* Saturday got relabeled "Our Lady's Saturday" right out from under the
|
||||
* octave commemoration that's supposed to govern it.
|
||||
*/
|
||||
function applyMarianSaturday(
|
||||
isoDate: string,
|
||||
weekday: ReturnType<typeof weekdayOf>,
|
||||
temporalCategory: TemporalCategory,
|
||||
winner: DayWinner,
|
||||
commemorations: Commemoration[],
|
||||
): DayWinner {
|
||||
if (weekday !== 'saturday' || temporalCategory !== 'ordinary-feria' || activeOctavesFor(isoDate).length > 0) {
|
||||
return winner;
|
||||
}
|
||||
const MARIAN_SATURDAY: DayWinner = { kind: 'temporal', id: 'marian-saturday' };
|
||||
if (winner.kind === 'temporal') {
|
||||
return MARIAN_SATURDAY;
|
||||
}
|
||||
if (isAtLeast(winner.rank, 'semiduplex')) {
|
||||
return winner;
|
||||
}
|
||||
commemorations.push({ kind: 'sanctoral', id: winner.id, name: winner.name, rank: winner.rank });
|
||||
return MARIAN_SATURDAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layered on top of everything above, not part of it: an octave doesn't
|
||||
* change how a single day's own precedence contest is decided, it just
|
||||
|
||||
Reference in New Issue
Block a user