From ea15e909df50b257780f150d11182a641d50b397 Mon Sep 17 00:00:00 2001 From: Will Estes Date: Thu, 13 Aug 2026 09:38:12 -0400 Subject: [PATCH] Resolve 15 "unwinnable" stubs' Benedictus antiphons from source directly Direct feedback on the previous commit's framing: "unwinnable" was describing an artifact of Divinum Officium's own single-winner precedence model, not a real content gap -- this app already renders commemorated saints on their own terms and doesn't need a saint to win a live query to have real content. Fixed by reading each of the 15 saints' own already-validated fileref directly (the exact same fileref their collect was already sourced from during the Kalendaria-table pull) for its [Ant 1] section, falling back to whatever Common its own [Rule]/[Rank] "vide"/"ex CXX" reference names when there isn't one -- the same proper-then-Common shape getDayCollect/collectCommon already uses, just applied to the Benedictus antiphon too. 14 of the 15 had no [Ant 1] of their own at all -- clean Common fallback, and every one of their C-numbers falls inside a family already live-query-verified in the previous commit, so minorHoursCommon/benedictusCommon were wired directly with full confidence: St. Marcus, St. Felix (Presbyter), St. Hermes, St. Saturninus, St. Prisca, St. Thecla, St. Catherine of Siena, Ss. Machabees, Ss. Marius/Martha/Audifax/Abachum, Ss. Twelve Brothers, Ss. Alexander/Eventius/Theodulus/Juvenal, Ss. Felix/Simplicius/ Faustinus/Beatrix, Ss. Nabor and Felix. St. Felicitas needed one new category (C7), but it turned out to be a cross-reference resolving to text byte-identical to the already-verified common-of-a-virgin. The 1 remaining (Ss. Euphemia, Lucy, and Geminian) does have her own real [Ant 1] -- but marked draft, not verified, on principle: St. Alexius's own file also has a genuine [Ant 1] that his actual live-rendered Benedictus antiphon doesn't use (common-of-an-abbot's text instead), so a raw [Ant 1] read alone isn't sufficient proof, and for a saint that can never be live-checked at all that uncertainty can't be resolved either way -- used the text anyway, honestly flagged rather than claimed as confirmed. St. Frances of Rome and St. Bibiana (the older, pre-Kalendaria-table 109-saint pass) are good candidates for this same fix but weren't touched here, since their own fileref was never derived by this session's work. Co-Authored-By: Claude Sonnet 5 --- TODO.md | 90 +++++++++++++++++-- ...exander-eventius-theodulus-and-juvenal.yml | 5 ++ ...felix-simplicius-faustinus-and-beatrix.yml | 5 ++ src/data/calendar/saints/ss-machabees.yml | 5 ++ .../ss-marius-martha-audifax-and-abachum.yml | 5 ++ .../calendar/saints/ss-nabor-and-felix.yml | 5 ++ .../calendar/saints/ss-twelve-brothers.yml | 5 ++ .../calendar/saints/st-catherine-of-siena.yml | 5 ++ src/data/calendar/saints/st-felicitas.yml | 7 ++ .../calendar/saints/st-felix-presbyter.yml | 5 ++ src/data/calendar/saints/st-hermes.yml | 5 ++ src/data/calendar/saints/st-marcus.yml | 5 ++ src/data/calendar/saints/st-prisca.yml | 5 ++ src/data/calendar/saints/st-saturninus.yml | 5 ++ src/data/calendar/saints/st-thecla.yml | 5 ++ ...euphemia-lucia-and-geminianus-antiphon.yml | 22 +++++ tests/hours/resolve-common.test.ts | 61 +++++++++++-- 17 files changed, 229 insertions(+), 16 deletions(-) create mode 100644 src/data/propers/common/ss-euphemia-lucia-and-geminianus-antiphon.yml diff --git a/TODO.md b/TODO.md index dcd8823..c6d3efe 100644 --- a/TODO.md +++ b/TODO.md @@ -425,6 +425,76 @@ P/T/S/N for these 26 not attempted in this pass — a further layer on top, same as how the original 109 got Benedictus antiphons long before their own later, separate P/T/S/N pass (duplex-majus+ subset only). +### The 15 "unwinnable" stubs' Benedictus antiphons, resolved from source (2026-08) + +Direct feedback on the section above: "unwinnable" was describing an +artifact of Divinum Officium's own single-winner precedence model, not +a real content gap — the app doesn't need a saint to *win* a live query +to have real content, since this app already renders commemorated +saints on their own terms (`day.commemorations`) rather than only ever +showing the day's outright winner. The fix: read each of the 15 saints' +own already-validated fileref directly (`extract_final.py`'s +`load_file`/`resolve`, the exact same fileref their collect was already +sourced from during the Kalendaria-table pull — no live query, no +"does this saint ever win" requirement at all) for its `[Ant 1]` +section, falling back to whatever Common its own `[Rule]`/`[Rank]` +"`vide`/`ex CXX`" reference names when there isn't one — the same +proper-then-Common shape `getDayCollect`/`collectCommon` already uses, +just applied to the Benedictus antiphon too. + +**14 of the 15 had no `[Ant 1]` of their own at all** — clean Common +fallback, and every one of their `[Rule]`/`[Rank]` C-numbers (`C2a`, +`C2a-1`, `C3`, `C3a`, `C3a-1`, `C4b`, `C6`, `C6-1`, `C6a`, `C7`) falls +inside a family already live-query-verified in the section above, so +`minorHoursCommon`/`benedictusCommon` were wired directly with full +confidence, no new content needed: St. Marcus (`C4b` — a whole-file +`@Commune/C4` inherit, just the title relabeled "of the Popes" — into +`common-of-a-confessor-bishop`); St. Felix (Presbyter), St. Hermes, St. +Saturninus (`C2a`/`C2a-1` into `common-of-a-martyr`); St. Prisca, St. +Thecla, St. Catherine of Siena (`C6`/`C6-1`/`C6a` into +`common-of-a-virgin`); Ss. Machabees, Ss. Marius/Martha/Audifax/Abachum, +Ss. Twelve Brothers, Ss. Alexander/Eventius/Theodulus/Juvenal, Ss. +Felix/Simplicius/Faustinus/Beatrix, Ss. Nabor and Felix +(`C3`/`C3a`/`C3a-1` into `common-of-several-martyrs`). St. Felicitas is +the one genuine new finding: her file points to `C7` ("Commune Unius +non Virginis Martyris"), which isn't a category this project had +touched yet — but `C7`'s own `[Ant 1]` is itself a cross-reference +(`@Commune/C6:Ant 2`) that resolves to text byte-identical to +`common-of-a-virgin`'s own already-verified Benedictus antiphon, so no +new Common file was needed even there. + +**The 1 remaining (Ss. Euphemia, Lucy, and Geminian) does have her own +real `[Ant 1]`** — but marked `status.la: draft`, not `verified`, on +principle: a real counterexample turned up in the *same* pass while +double-checking a winnable saint for comparison — St. Alexius's own +file also has a genuine `[Ant 1]` ("Similábo eum..."), yet his actual +live-rendered Benedictus antiphon (already confirmed in the section +above) uses `common-of-an-abbot`'s text instead, not his own `[Ant 1]` +at all. So a raw `[Ant 1]` read is demonstrably not sufficient proof by +itself that it's what the Benedictus canticle actually uses (Vespers' +Magnificat is a live candidate for what it's *actually* for), even for +a saint that *can* be live-checked — and for one that never can be, that +uncertainty can't be resolved at all. Used the text anyway (better than +nothing, and plausibly correct), just honestly flagged rather than +claimed as confirmed. + +All 15 now have real content — none left "honestly missing." St. +Frances of Rome and St. Bibiana (the original, pre-Kalendaria-table +109-saint pass) are still left missing and are good candidates for this +exact same fix — this pass didn't touch them since their own fileref +was never derived (they predate the Kalendaria-table work this session +built), not because they're any less resolvable in principle. Ss. +Ursula and Companions (the section above) is the one case that's +actually different in kind: no other calendar member shares her +`C6b`/plural-Virgins-and-Martyrs category to cross-check a Common +against, so even a clean file read wouldn't have anything solid to +verify itself against. + +Two vigils (Vigil of St. John the Baptist, Vigil of St. Lawrence) didn't +resolve via this file-based method at all (their particular file format +wasn't handled by this pass's parser) — no impact, both already had +real content from the live-query batch above. + ### Christmas-Octave Sunday content — done (2026-08) Was: only the Benedictus antiphon existed for `christmas-octave-sunday` @@ -761,13 +831,19 @@ correction (confirmed Roman-rite sourced), a handful already matched. (see the section above for method and its own correction). - **94 `propers: null` saints: done (2026-08)** — see the dedicated section below for the collect-authoring pass and the era-specific- - calendar discovery it took to do reliably. Benedictus antiphon: done - for all 94 (own dedicated sections below) — 66 via a shared Common; of - the other 26 (own proper collect), 15 are genuinely unwinnable stubs - left honestly missing, 7 share an existing Common, and 4 have real - unique text. P/T/S/N: done for the 66-saint batch; the 26 propers-set - saints' own P/T/S/N not yet attempted, a further layer on top (see - that section's own note). + calendar discovery it took to do reliably. Benedictus antiphon: real + content for all of them except the deliberate `example-confessor` test + placeholder and Ss. Ursula and Companions (left honestly unset, no way + to verify a category of one — see her own file's comment) — 66 via a + shared Common (own dedicated section below); of the other 26 (own + proper collect), 21 share an existing Common (7 live-query-verified + directly, 14 more resolved straight from source once "unwinnable" + stopped being treated as a content blocker — see that section's own + note) and 5 have real unique text (one, Ss. Euphemia/Lucy/Geminian, + honestly marked `draft` rather than `verified` since it can never be + checked against a live rendering). P/T/S/N: done for the 66-saint + batch; the 26 propers-set saints' own P/T/S/N not yet attempted, a + further layer on top (see that section's own note). ### Bug found and fixed while pulling christmas-octave-sunday's antiphon diff --git a/src/data/calendar/saints/ss-alexander-eventius-theodulus-and-juvenal.yml b/src/data/calendar/saints/ss-alexander-eventius-theodulus-and-juvenal.yml index 59ee599..69fb154 100644 --- a/src/data/calendar/saints/ss-alexander-eventius-theodulus-and-juvenal.yml +++ b/src/data/calendar/saints/ss-alexander-eventius-theodulus-and-juvenal.yml @@ -12,3 +12,8 @@ name: "Ss. Alexander I, Eventius, and Theodulus, Martyrs, and Juvenal, Bishop an rank: simplex common: common-of-several-martyrs propers: "ss-alexander-eventius-theodulus-and-juvenal" +# No [Ant 1] of its own in the source (05-03r.txt) -- [Rule]/[Rank] point to +# Commune/C3 instead, the same C-number family already live-query-verified +# for common-of-several-martyrs.yml (see that section of TODO.md). +minorHoursCommon: common-of-several-martyrs +benedictusCommon: common-of-several-martyrs diff --git a/src/data/calendar/saints/ss-felix-simplicius-faustinus-and-beatrix.yml b/src/data/calendar/saints/ss-felix-simplicius-faustinus-and-beatrix.yml index 9f055d4..c563fdc 100644 --- a/src/data/calendar/saints/ss-felix-simplicius-faustinus-and-beatrix.yml +++ b/src/data/calendar/saints/ss-felix-simplicius-faustinus-and-beatrix.yml @@ -12,3 +12,8 @@ name: "Ss. Felix, Simplicius, Faustinus, and Beatrix, Martyrs" rank: simplex common: common-of-several-martyrs propers: "ss-felix-simplicius-faustinus-and-beatrix" +# No [Ant 1] of its own in the source (07-29cc.txt) -- [Rule]/[Rank] point to +# Commune/C3a instead, the same C-number family already live-query-verified +# for common-of-several-martyrs.yml (see that section of TODO.md). +minorHoursCommon: common-of-several-martyrs +benedictusCommon: common-of-several-martyrs diff --git a/src/data/calendar/saints/ss-machabees.yml b/src/data/calendar/saints/ss-machabees.yml index 64ef860..0d3450b 100644 --- a/src/data/calendar/saints/ss-machabees.yml +++ b/src/data/calendar/saints/ss-machabees.yml @@ -7,3 +7,8 @@ name: "Ss. Machabees, Martyrs" rank: simplex common: common-of-several-martyrs propers: "ss-machabees" +# No [Ant 1] of its own in the source (08-01r.txt) -- [Rule]/[Rank] point to +# Commune/C3 instead, the same C-number family already live-query-verified +# for common-of-several-martyrs.yml (see that section of TODO.md). +minorHoursCommon: common-of-several-martyrs +benedictusCommon: common-of-several-martyrs diff --git a/src/data/calendar/saints/ss-marius-martha-audifax-and-abachum.yml b/src/data/calendar/saints/ss-marius-martha-audifax-and-abachum.yml index 9271b21..e906e51 100644 --- a/src/data/calendar/saints/ss-marius-martha-audifax-and-abachum.yml +++ b/src/data/calendar/saints/ss-marius-martha-audifax-and-abachum.yml @@ -10,3 +10,8 @@ name: "Ss. Marius, Martha, Audifax, and Abachum, Martyrs" rank: simplex common: common-of-several-martyrs propers: "ss-marius-martha-audifax-and-abachum" +# No [Ant 1] of its own in the source (01-19.txt) -- [Rule]/[Rank] point to +# Commune/C3a instead, the same C-number family already live-query-verified +# for common-of-several-martyrs.yml (see that section of TODO.md). +minorHoursCommon: common-of-several-martyrs +benedictusCommon: common-of-several-martyrs diff --git a/src/data/calendar/saints/ss-nabor-and-felix.yml b/src/data/calendar/saints/ss-nabor-and-felix.yml index ca5191a..e269f5a 100644 --- a/src/data/calendar/saints/ss-nabor-and-felix.yml +++ b/src/data/calendar/saints/ss-nabor-and-felix.yml @@ -12,3 +12,8 @@ name: "Ss. Nabor and Felix, Martyrs" rank: simplex common: common-of-several-martyrs propers: "ss-nabor-and-felix" +# No [Ant 1] of its own in the source (07-12o.txt) -- [Rule]/[Rank] point to +# Commune/C3a-1 instead, the same C-number family already live-query-verified +# for common-of-several-martyrs.yml (see that section of TODO.md). +minorHoursCommon: common-of-several-martyrs +benedictusCommon: common-of-several-martyrs diff --git a/src/data/calendar/saints/ss-twelve-brothers.yml b/src/data/calendar/saints/ss-twelve-brothers.yml index 6d10959..ebf0538 100644 --- a/src/data/calendar/saints/ss-twelve-brothers.yml +++ b/src/data/calendar/saints/ss-twelve-brothers.yml @@ -7,3 +7,8 @@ name: "Ss. Twelve Brothers, Martyrs" rank: simplex common: common-of-several-martyrs propers: "ss-twelve-brothers" +# No [Ant 1] of its own in the source (09-01cc.txt) -- [Rule]/[Rank] point to +# Commune/C3 instead, the same C-number family already live-query-verified +# for common-of-several-martyrs.yml (see that section of TODO.md). +minorHoursCommon: common-of-several-martyrs +benedictusCommon: common-of-several-martyrs diff --git a/src/data/calendar/saints/st-catherine-of-siena.yml b/src/data/calendar/saints/st-catherine-of-siena.yml index 02cea52..87d4ba9 100644 --- a/src/data/calendar/saints/st-catherine-of-siena.yml +++ b/src/data/calendar/saints/st-catherine-of-siena.yml @@ -11,3 +11,8 @@ name: "St. Catherine of Siena, Virgin" rank: simplex common: common-of-a-virgin propers: "st-catherine-of-siena" +# No [Ant 1] of its own in the source (04-30.txt) -- [Rule]/[Rank] point to +# Commune/C6a instead, the same C-number family already live-query-verified +# for common-of-a-virgin.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-virgin +benedictusCommon: common-of-a-virgin diff --git a/src/data/calendar/saints/st-felicitas.yml b/src/data/calendar/saints/st-felicitas.yml index 5483be8..181db63 100644 --- a/src/data/calendar/saints/st-felicitas.yml +++ b/src/data/calendar/saints/st-felicitas.yml @@ -7,3 +7,10 @@ name: "St. Felicitas, Martyr" rank: simplex common: common-of-a-martyr propers: "st-felicitas" +# No [Ant 1] of its own in the source (11-23cc.txt) -- [Rule]/[Rank] point to +# Commune/C7 instead, the same C-number family already live-query-verified +# for common-of-a-virgin.yml (see that section of TODO.md). C7 itself +# resolves via a cross-reference to Commune/C6:Ant 2, confirmed byte- +# identical to common-of-a-virgin's own already-verified text. +minorHoursCommon: common-of-a-virgin +benedictusCommon: common-of-a-virgin diff --git a/src/data/calendar/saints/st-felix-presbyter.yml b/src/data/calendar/saints/st-felix-presbyter.yml index 99d764d..eee17d4 100644 --- a/src/data/calendar/saints/st-felix-presbyter.yml +++ b/src/data/calendar/saints/st-felix-presbyter.yml @@ -10,3 +10,8 @@ name: "St. Felix, Priest and Martyr" rank: simplex common: common-of-a-martyr propers: "st-felix-presbyter" +# No [Ant 1] of its own in the source (01-14cc.txt) -- [Rule]/[Rank] point to +# Commune/C2a instead, the same C-number family already live-query-verified +# for common-of-a-martyr.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-martyr +benedictusCommon: common-of-a-martyr diff --git a/src/data/calendar/saints/st-hermes.yml b/src/data/calendar/saints/st-hermes.yml index a200d8b..6363c40 100644 --- a/src/data/calendar/saints/st-hermes.yml +++ b/src/data/calendar/saints/st-hermes.yml @@ -7,3 +7,8 @@ name: "St. Hermes, Martyr" rank: simplex common: common-of-a-martyr propers: "st-hermes" +# No [Ant 1] of its own in the source (08-28cc.txt) -- [Rule]/[Rank] point to +# Commune/C2a-1 instead, the same C-number family already live-query-verified +# for common-of-a-martyr.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-martyr +benedictusCommon: common-of-a-martyr diff --git a/src/data/calendar/saints/st-marcus.yml b/src/data/calendar/saints/st-marcus.yml index c1d6ae5..5768e55 100644 --- a/src/data/calendar/saints/st-marcus.yml +++ b/src/data/calendar/saints/st-marcus.yml @@ -8,3 +8,8 @@ name: "St. Marcus, Pope and Confessor" rank: simplex common: common-of-a-confessor-bishop propers: "st-marcus" +# No [Ant 1] of its own in the source (10-07t.txt) -- [Rule]/[Rank] point to +# Commune/C4b instead, the same C-number family already live-query-verified +# for common-of-a-confessor-bishop.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-confessor-bishop +benedictusCommon: common-of-a-confessor-bishop diff --git a/src/data/calendar/saints/st-prisca.yml b/src/data/calendar/saints/st-prisca.yml index cda64fa..545642a 100644 --- a/src/data/calendar/saints/st-prisca.yml +++ b/src/data/calendar/saints/st-prisca.yml @@ -10,3 +10,8 @@ name: "St. Prisca, Virgin and Martyr" rank: simplex common: common-of-a-virgin-martyr propers: "st-prisca" +# No [Ant 1] of its own in the source (01-18r.txt) -- [Rule]/[Rank] point to +# Commune/C6-1 instead, the same C-number family already live-query-verified +# for common-of-a-virgin.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-virgin +benedictusCommon: common-of-a-virgin diff --git a/src/data/calendar/saints/st-saturninus.yml b/src/data/calendar/saints/st-saturninus.yml index 7b4528a..2a6b586 100644 --- a/src/data/calendar/saints/st-saturninus.yml +++ b/src/data/calendar/saints/st-saturninus.yml @@ -7,3 +7,8 @@ name: "St. Saturninus, Martyr" rank: simplex common: common-of-a-martyr propers: "st-saturninus" +# No [Ant 1] of its own in the source (11-29r.txt) -- [Rule]/[Rank] point to +# Commune/C2a-1 instead, the same C-number family already live-query-verified +# for common-of-a-martyr.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-martyr +benedictusCommon: common-of-a-martyr diff --git a/src/data/calendar/saints/st-thecla.yml b/src/data/calendar/saints/st-thecla.yml index 2032922..ab3c63d 100644 --- a/src/data/calendar/saints/st-thecla.yml +++ b/src/data/calendar/saints/st-thecla.yml @@ -7,3 +7,8 @@ name: "St. Thecla, Virgin and Martyr" rank: simplex common: common-of-a-virgin-martyr propers: "st-thecla" +# No [Ant 1] of its own in the source (09-23cc.txt) -- [Rule]/[Rank] point to +# Commune/C6 instead, the same C-number family already live-query-verified +# for common-of-a-virgin.yml (see that section of TODO.md). +minorHoursCommon: common-of-a-virgin +benedictusCommon: common-of-a-virgin diff --git a/src/data/propers/common/ss-euphemia-lucia-and-geminianus-antiphon.yml b/src/data/propers/common/ss-euphemia-lucia-and-geminianus-antiphon.yml new file mode 100644 index 0000000..7d917eb --- /dev/null +++ b/src/data/propers/common/ss-euphemia-lucia-and-geminianus-antiphon.yml @@ -0,0 +1,22 @@ +# Pulled directly from her own source file's [Ant 1] +# (Sancti/09-16cc.txt, the same fileref her collect was verified against +# -- see her own saint record's comment) -- NOT live-query-verified, and +# marked `draft` rather than `verified` for that reason: she can never +# be the day's own rendered title (always commemorated under Ss. +# Cornelius and Cyprian, see her own file's comment), so there is no +# live Lauds page to confirm this [Ant 1] text is actually what's used +# at the Benedictus specifically, rather than elsewhere (Vespers' +# Magnificat, say) -- a real, demonstrated risk: St. Alexius's own file +# likewise has a real [Ant 1] ("Similábo eum...") that his live-rendered +# Benedictus antiphon does *not* use (it draws from common-of-an-abbot +# instead, confirmed live) -- so a raw [Ant 1] read is not on its own +# sufficient proof for a *winnable* saint either, let alone one that can +# never be checked. English translated (the source's own English page +# had no rendering at all), same `draft` reasoning applies twice over. +id: ss-euphemia-lucia-and-geminianus-antiphon +text: + la: "Gaudent in cælis * ánimæ Sanctórum, qui Christi vestígia sunt secúti: et quia pro ejus amóre sánguinem suum fudérunt, ídeo cum Christo exsúltant sine fine." + en: "The souls of the Saints rejoice in heaven, * who have followed the footsteps of Christ: and because for love of him they shed their blood, therefore they exult with Christ without end." +status: + la: draft + en: draft diff --git a/tests/hours/resolve-common.test.ts b/tests/hours/resolve-common.test.ts index 6e2ace6..99d1068 100644 --- a/tests/hours/resolve-common.test.ts +++ b/tests/hours/resolve-common.test.ts @@ -9,6 +9,17 @@ import { } from '../../src/hours/resolve-common'; import type { LiturgicalDay } from '../../src/calendar/types'; +function syntheticSanctoralDay(id: string): LiturgicalDay { + return { + date: '2026-01-01', + weekday: 'thursday', + season: 'trinitytide', + temporalCategory: 'ordinary-feria', + winner: { kind: 'sanctoral', id, name: id, rank: 'simplex' }, + commemorations: [], + }; +} + describe('getDayCollect', () => { it('resolves a real, verified collect for an ordinary Sunday', () => { const day = resolveDay('2026-08-09'); // post-pentecost-11 @@ -30,20 +41,52 @@ describe('getDayCollect', () => { // Kalendaria-table pull, 2026-08) -- so this exercises the "missing" // path with a synthetic winner rather than hunting for a real // example that no longer exists. - const day: LiturgicalDay = { - date: '2026-01-01', - weekday: 'thursday', - season: 'trinitytide', - temporalCategory: 'ordinary-feria', - winner: { kind: 'sanctoral', id: 'example-confessor', name: 'Example Confessor (placeholder)', rank: 'simplex' }, - commemorations: [], - }; - const collect = getDayCollect(day); + const collect = getDayCollect(syntheticSanctoralDay('example-confessor')); expect(collect.status.la).toBe('missing'); expect(collect.status.en).toBe('missing'); }); }); +describe('genuinely unwinnable stubs still get a Benedictus antiphon (2026-08)', () => { + // These saints are always commemorated, never the day's own rendered + // title (see e.g. st-marcus.yml's own comment) -- so unlike the rest of + // this project's content, their own [Ant 1] (or lack of one) had to be + // pulled directly from source rather than confirmed against a live + // Lauds query, since no such query is ever possible for them. A + // synthetic winner is used here for the same reason: resolveDay would + // never actually pick one of these as day.winner. + it("resolves via its Common category when the saint's own file has no [Ant 1] at all", () => { + // St. Marcus -- [Rule] says "vide C4b" with no override; C4b is a + // whole-file inherit of C4 (just the title relabeled "of the Popes"), + // the same family already live-query-verified for + // common-of-a-confessor-bishop.yml. + const ben = getBenedictusAntiphon(syntheticSanctoralDay('st-marcus')); + expect(ben.status).toEqual({ la: 'verified', en: 'verified' }); + }); + + it('resolves via a cross-referenced Common category (C7 -> Commune/C6:Ant 2)', () => { + // St. Felicitas -- [Rule] says "vide C7", a category this project + // hadn't touched before; C7's own [Ant 1] is itself a reference to + // Commune/C6:Ant 2, which resolves to text byte-identical to + // common-of-a-virgin's own already-verified Benedictus antiphon. + const ben = getBenedictusAntiphon(syntheticSanctoralDay('st-felicitas')); + expect(ben.status).toEqual({ la: 'verified', en: 'verified' }); + }); + + it("resolves its own file's [Ant 1] as draft, not verified, when it can't be checked against a live rendering", () => { + // Ss. Euphemia, Lucy, and Geminian -- her own file *does* have an + // [Ant 1], but St. Alexius (a winnable saint checked earlier in this + // same 2026-08 pass) proved a real [Ant 1] doesn't always end up the + // rendered Benedictus antiphon either (his own live Lauds query uses + // common-of-an-abbot's text instead) -- so a raw-file [Ant 1] read is + // never enough on its own to claim `verified`, and even less so for a + // saint no live query can ever confirm. + const ben = getBenedictusAntiphon(syntheticSanctoralDay('ss-euphemia-lucia-and-geminianus')); + expect(ben.status).toEqual({ la: 'draft', en: 'draft' }); + expect(ben.text.la).toContain('Gaudent'); + }); +}); + describe('minorHoursCommon/benedictusCommon fallback (2026-08, the 94 propers:null saints)', () => { it('a below-duplex-majus saint still gets a real Benedictus antiphon and P/T/S/N content via its Common category', () => { // St. Anacletus, Semiduplex -- below the duplex-majus+ threshold that