Add octave tier to Matins invitatory resolution, close Nov 8/13 gaps

The Octave Day of All Saints (Nov 8) and All Saints of the Benedictine
Order (Nov 13) are each their own separate sanctoral record with a fake
"proper-to-*" common, cross-referencing All Saints' own proper text in
the reference source. resolveMatinsInvitatoryText had no octave tier
(unlike resolveMatinsHymn, which already had one), so Nov 8 fell through
to the plain ferial default instead of reusing All Saints' own text.
Restored the tier to match resolveMatinsHymn's, and authored Nov 13's
own file directly since its source cross-references All Saints outright.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGsATZvfnpQ81HQuoF5JuL
This commit is contained in:
2026-09-05 21:39:34 -04:00
parent 104c07f8aa
commit e7d66df3d4
2 changed files with 37 additions and 11 deletions
@@ -0,0 +1,11 @@
# web/www/horas/Latin/SanctiM/11-13M.txt's own [Invit] is a direct
# cross-reference to @Sancti/11-01 (All Saints' own text) -- authored
# here directly since it's the actual text this feast uses, not a
# private duplicate (same reasoning as matins-invitatory-all-saints.yml).
id: matins-invitatory-all-saints-of-the-benedictine-order
text:
la: "Regem regum Dóminum veníte adorémus: * Quia ipse est coróna Sanctórum ómnium."
en: "O come, let us worship the Lord, the King of kings, * for He is Himself the Crown of all the Saints."
status:
la: verified
en: verified
+26 -11
View File
@@ -285,17 +285,25 @@ function psalmRefParts(refs: PsalmRef[]): ResolvedPart[] {
})); }));
} }
/** The invitatory antiphon's own text — same override > Common-category > /** The invitatory antiphon's own text — same override > octave > Common-
* seasonal > ferial precedence as `resolveMatinsHymn`, minus the octave * category > seasonal > ferial precedence as `resolveMatinsHymn`. The
* tier: no per-octave invitatory-antiphon override exists anywhere in the * octave tier was originally omitted here on the reasoning that no
* reference source (unlike the hymn, which genuinely persists all week on * per-octave invitatory-antiphon override exists anywhere in the
* some octaves) — an octave day already falls through correctly to its * reference source and an octave day already falls through correctly to
* governing saint's own Common/season tier here, so adding an octave tier * its governing saint's own Common/season tier — true for an *ordinary*
* would have nothing to fire on. Keeps the existing ferial fallback id * within-octave day, which reuses the original feast's own record as its
* (`matins-invitatory-antiphon`) as-is rather than renaming it to match * winner. It's false for an octave's own literal *closing* day, which is
* the hymn's `-ferial` convention — it's already `verified` and its own * a wholly separate sanctoral record with its own id (e.g. `all-saints`'s
* header already documents itself as the fallback-of-record; renaming * `octave-of-all-saints`, Nov 8) and a fake `proper-to-*` `common` — that
* would be pure churn. * record's own override lookup misses, there's no real Common to fall
* back to, and it used to land on the plain ferial default instead of the
* original feast's genuine proper invitatory (live-verified live-CGI
* mismatch, 2026-09-06). Restored to match `resolveMatinsHymn`'s tier
* exactly, since the underlying gap was the same shape.
* Keeps the existing ferial fallback id (`matins-invitatory-antiphon`) as-
* is rather than renaming it to match the hymn's `-ferial` convention —
* it's already `verified` and its own header already documents itself as
* the fallback-of-record; renaming would be pure churn.
* *
* Doubling (`isDoubleOrHigher`, via `openingAntiphon`) is a separate, final * Doubling (`isDoubleOrHigher`, via `openingAntiphon`) is a separate, final
* step applied to whichever tier's text wins here — never part of content * step applied to whichever tier's text wins here — never part of content
@@ -308,6 +316,13 @@ function resolveMatinsInvitatoryText(day: LiturgicalDay): ResolvedText {
return proper; return proper;
} }
} }
const octave = resolveActiveOctave(day.date);
if (octave) {
const octaveInvitatory = resolveCommon(`matins-invitatory-${octave.id}`);
if (octaveInvitatory.status.la !== 'missing' || octaveInvitatory.status.en !== 'missing') {
return octaveInvitatory;
}
}
const winner = resolveOfficeWinner(day); const winner = resolveOfficeWinner(day);
const saint = winner.kind === 'sanctoral' ? getSaintRecord(winner.id) : undefined; const saint = winner.kind === 'sanctoral' ? getSaintRecord(winner.id) : undefined;
const commonId = saint?.common; const commonId = saint?.common;