calendar: model Our Lady's Saturday as a real occurrence outcome
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:
2026-08-11 14:02:55 -04:00
parent 4548042b65
commit 747a078580
16 changed files with 378 additions and 31 deletions
+11
View File
@@ -13,6 +13,7 @@ import type { LiturgicalDay } from './types';
import { easterSunday } from './easter';
import { adventStart, firstSundayStrictlyAfter, sundayOnOrBefore } from './temporal';
import { addDays, daysBetween, toIsoDate } from './date-math';
import { getTemporalFeastRecord } from './temporal-feasts';
function capitalize(text: string): string {
return text.charAt(0).toUpperCase() + text.slice(1);
@@ -136,6 +137,16 @@ export function getDayLabel(day: LiturgicalDay): string {
return day.winner.name;
}
// A named temporal feast (Christmas, Pentecost, Marian Saturday, ...)
// shows its own name rather than the ordinal week label — same
// "winner displaces, doesn't combine" rule a sanctoral winner gets
// above. Most temporal ids don't have a record at all (see
// temporal-feasts.ts) and fall through to the ordinal label as before.
const namedFeast = getTemporalFeastRecord(day.winner.id);
if (namedFeast) {
return namedFeast.name;
}
const temporal = temporalLabel(day);
const commemorated = day.commemorations.find((c) => c.kind === 'sanctoral');
return commemorated ? `${commemorated.name}${temporal}` : temporal;