From e7d66df3d440394bce19c9dfbf98a92b7a7913f8 Mon Sep 17 00:00:00 2001 From: Will Estes Date: Sat, 5 Sep 2026 21:39:34 -0400 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_01LGsATZvfnpQ81HQuoF5JuL --- ...ry-all-saints-of-the-benedictine-order.yml | 11 ++++++ src/hours/matins.ts | 37 +++++++++++++------ 2 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 src/data/propers/common/matins-invitatory-all-saints-of-the-benedictine-order.yml diff --git a/src/data/propers/common/matins-invitatory-all-saints-of-the-benedictine-order.yml b/src/data/propers/common/matins-invitatory-all-saints-of-the-benedictine-order.yml new file mode 100644 index 0000000..529836a --- /dev/null +++ b/src/data/propers/common/matins-invitatory-all-saints-of-the-benedictine-order.yml @@ -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 diff --git a/src/hours/matins.ts b/src/hours/matins.ts index ca85dd3..5fc6272 100644 --- a/src/hours/matins.ts +++ b/src/hours/matins.ts @@ -285,17 +285,25 @@ function psalmRefParts(refs: PsalmRef[]): ResolvedPart[] { })); } -/** The invitatory antiphon's own text — same override > Common-category > - * seasonal > ferial precedence as `resolveMatinsHymn`, minus the octave - * tier: no per-octave invitatory-antiphon override exists anywhere in the - * reference source (unlike the hymn, which genuinely persists all week on - * some octaves) — an octave day already falls through correctly to its - * governing saint's own Common/season tier here, so adding an octave tier - * would have nothing to fire on. 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. +/** The invitatory antiphon's own text — same override > octave > Common- + * category > seasonal > ferial precedence as `resolveMatinsHymn`. The + * octave tier was originally omitted here on the reasoning that no + * per-octave invitatory-antiphon override exists anywhere in the + * reference source and an octave day already falls through correctly to + * its governing saint's own Common/season tier — true for an *ordinary* + * within-octave day, which reuses the original feast's own record as its + * winner. It's false for an octave's own literal *closing* day, which is + * a wholly separate sanctoral record with its own id (e.g. `all-saints`'s + * `octave-of-all-saints`, Nov 8) and a fake `proper-to-*` `common` — that + * 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 * step applied to whichever tier's text wins here — never part of content @@ -308,6 +316,13 @@ function resolveMatinsInvitatoryText(day: LiturgicalDay): ResolvedText { 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 saint = winner.kind === 'sanctoral' ? getSaintRecord(winner.id) : undefined; const commonId = saint?.common;