Add per-feast Vespers office overrides for all 30 duplex-majus+ ids

Same eligibility rule as Lauds' psalmody override (a duplex-majus+
saint, or a named temporal feast), factored out to
resolve-common.ts's getOfficeOverrideId since Vespers has no
psalmody-override table of its own to piggyback eligibility on.

Authored via one live command=prayVespera query per id, reusing the
same clean per-saint dates already established for each one's Lauds
office-bundle override. The capitulum turned out to be byte-identical
between Lauds and Vespers for every one of the 30 ids checked, a real
Monastic-rite fact rather than a coincidence — so no
vespers-capitulum-<id>.yml files exist at all; the chapter falls
through to the already-authored lauds-capitulum-<id> directly instead
of duplicating identical content.

St. Scholastica's Vespers responsory, hymn, and versicle needed a hand
translation (same gap she has at Lauds/Terce/Sext/None — the reference
engine has no English for any of her proper content). Two more
one-line English gaps in the shared Immaculate Conception/Nativity of
the BVM responsory were filled with the standard Douay-Rheims/Ave
Maria wording.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-13 21:31:59 -04:00
parent 4d88568c42
commit 53582f1ded
94 changed files with 2962 additions and 34 deletions
+46 -6
View File
@@ -1,4 +1,4 @@
import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart } from './types';
import type { HourDefinition, HourPart, ResolvedOrdo, ResolvedPart, ResolvedText } from './types';
import type { LiturgicalDay, Weekday } from '../calendar/types';
import { resolveEveningDay } from '../calendar/vespers';
import { getDayLabel } from '../calendar/day-label';
@@ -14,6 +14,7 @@ import {
verifiedText,
seasonalOfficeSuffix,
isFerialOrVigil,
getOfficeOverrideId,
} from './resolve-common';
import vespersDefinitionData from '../data/hours/vespers.yml';
import vespersAntiphonsData from '../data/hours/vespers-antiphons.yml';
@@ -81,13 +82,52 @@ function vespersVersicleId(weekday: Weekday): string {
return weekday === 'saturday' ? 'vespers-versicle-saturday' : 'vespers-versicle-sunday-ferial';
}
/** A per-feast override's chapter: `vespers-capitulum-${id}` when
* authored, else the already-authored `lauds-capitulum-${id}` directly —
* live-verified across all 30 duplex-majus+ saints/named-temporal ids
* with a Vespers office override (2026-08 sweep, `command=prayVespera`,
* each saint's own already-established clean date): the capitulum is
* byte-identical between Lauds and Vespers for every one of them, a real
* Monastic-rite fact (the reading doesn't change between the two hours,
* only the responsory/hymn/versicle do), not a coincidence specific to
* the ones checked. So no `vespers-capitulum-<id>.yml` files were
* authored at all — this falls straight through to the Lauds one instead
* of duplicating identical content into a second file per id. */
function vespersCapitulumForOverride(id: string): ResolvedText {
const proper = resolveCommon(`vespers-capitulum-${id}`);
if (proper.status.la !== 'missing' || proper.status.en !== 'missing') {
return proper;
}
return resolveCommon(`lauds-capitulum-${id}`);
}
/** The chapter/responsory/hymn/versicle bundle following the psalmody —
* see hours/types.ts's 'vespers-office' doc comment. No per-feast
* override mechanism yet, unlike Lauds' resolveOffice. Falls to a
* *seasonal* default first (Advent/Lent/Passiontide/Paschaltide — see
* resolve-common.ts's seasonalOfficeSuffix), then the plain weekday
* default. */
* see hours/types.ts's 'vespers-office' doc comment. A duplex-majus+
* saint's own proper bundle (chapter via vespersCapitulumForOverride
* above, responsory/hymn/versicle via `vespers-{part}-${id}`), or one of
* the named temporal feasts eligible via resolve-common.ts's
* getOfficeOverrideId, wins first when authored — same eligible-but-not-
* gated-on-content pattern as Lauds' resolveOffice, just without a
* psalmody-override table of its own to piggyback eligibility on
* (Vespers has no per-feast psalmody override mechanism — see TODO.md).
* Falls to a *seasonal* default next (Advent/Lent/Passiontide/
* Paschaltide — see resolve-common.ts's seasonalOfficeSuffix), and only
* then the plain weekday default — a feast's own override always wins
* over the season it happens to fall in, same as everywhere else in this
* codebase. */
function resolveOffice(day: LiturgicalDay): ResolvedPart[] {
const overrideId = getOfficeOverrideId(day);
if (overrideId) {
const chapter = vespersCapitulumForOverride(overrideId);
if (chapter.status.la !== 'missing' || chapter.status.en !== 'missing') {
return [
{ kind: 'chapter', text: chapter },
{ kind: 'responsory', text: resolveCommon(`vespers-responsory-${overrideId}`) },
{ kind: 'hymn', text: resolveCommon(`vespers-hymn-${overrideId}`) },
{ kind: 'versicle', text: resolveCommon(`vespers-versicle-${overrideId}`) },
];
}
}
const seasonSuffix = seasonalOfficeSuffix(day.season);
const key = seasonSuffix ?? day.weekday;
return [