diff --git a/TODO.md b/TODO.md index 9e21ec6..5d200ce 100644 --- a/TODO.md +++ b/TODO.md @@ -4653,3 +4653,55 @@ season-wide overrides, ahead of the plain default. New regression tests in `tests/hours/matins.test.ts` (`Sunday within the Octave of Ascension`) assert both the calendar winner (Sunday over the saint) and the full Matins content. `npm test` (821 passed), `tsc --noEmit`, and `npm run build` all pass. + +### Full sweep of `temporal-categories.yml` — two more real bugs found and fixed (2026-09-01) + +Follow-up, same day: user pushed back hard on the "not a bug" framing above ("the immaculate +conception transfer is correct... annuncition should transfer") and asked to sweep every +remaining unverified entry in `data/calendar/temporal-categories.yml`, not just the one already +fixed. Found two more real, calendar-wide bugs: + +1. **`commemorations.ts`'s `privileged-sunday` case itself was wrong**, not just one season's + tag. It gave any duplex-majus+ candidate a bare commemoration instead of transferring — + never actually verified against a primary source. Live-checked 3 independent cases: the + Immaculate Conception (Duplex I. classis) transfers off Advent II with **no** commemoration + (2024/2030/2041); the Annunciation (also Duplex I. classis) transfers off both Palm Sunday + and Easter Sunday itself the same way (2029/2035/2040/2046). Confirmed by direct instruction + as correct (with a known follow-on: the Annunciation's *real* rule jumps it past the whole + Easter Octave rather than the next open day, which lands inside it — blocked on the + not-yet-built Easter-octave mechanism, noted but not built here). Fixed: `privileged-sunday` + now transfers every rank unconditionally, no exception. + +2. **`eastertide`'s own `sunday` tier was backwards** — coded `privileged-sunday`, should be + `ordinary-sunday` for the *ordinary* Sundays after Easter (not Easter Day itself, not within + its Octave, both already separately handled). Live-verified twice: the Finding of the Holy + Cross (Duplex-II-classis, 2026-05-03) and St. Mark (Duplex-II-classis, 2027-04-25) both win + outright over "Dominica IV Post Pascha," with the Sunday merely noted as a `Tempora` line + underneath — exactly `ordinary-sunday`'s rule. Easter Day itself still needs the stronger + tier (confirmed by the Annunciation evidence above), so it's now special-cased directly in + `calendar/temporal.ts`'s `resolveTemporalCategory` (Sundays never consult `offsets`, so this + couldn't be expressed as a plain offset entry the way every other exception in that file is). + +**Six test failures from the `privileged-sunday` fix, all genuine fallout, not regressions** — +each test had encoded the old, wrong "commemorated in place" behavior as its expected value: +St. Andrew (Duplex II. classis) no longer commemorated alongside Advent I, but shown +transferred away (landing on Dec 1, where he now wins outright — `privileged-feria-minor`'s +Semiduplex+ threshold easily clears); St. Antoninus similarly now wins outright on his own day +(the real Easter-6 Sunday) instead of being pushed to the next day by the old wrong rule. All +six tests updated to real, live-verified dates/values, not just loosened to pass. + +**Remaining entries in the file, not independently live-collision-tested but documented as +such** (each has its own comment now): the Vigil of Pentecost and Vigil of Christmas +(`privileged-feria-major`) are corroborated by their own formal rank in the reference source +("Semiduplex I classis" / "Duplex I classis" respectively) rather than a live saint collision, +which is rare by construction; Pentecost Sunday itself (`privileged-sunday`) is consistent with +the confirmed "great octave Sunday" pattern but has no fixed-date-saint collision to test +against; Corpus Christi/Sacred Heart's `feria` (`privileged-feria-major`) shares the same +"feast of the Lord" reasoning already confirmed elsewhere, and their `sunday` key is flagged as +genuinely unreachable (both are always fixed weekdays, never a Sunday, per +`easter-offsets.yml`'s own `days:` table). Every other `feria` entry is the trivial +`ordinary-feria` default (no rank threshold — any real content wins), already implicitly +exercised correctly across hundreds of ordinary weekdays in the existing test suite. + +`npm test` (820 passed — one net fewer than before since two tests merged into one clearer +case), `tsc --noEmit`, and `npm run build` all pass. diff --git a/src/calendar/commemorations.ts b/src/calendar/commemorations.ts index 56a312f..192be9a 100644 --- a/src/calendar/commemorations.ts +++ b/src/calendar/commemorations.ts @@ -188,13 +188,22 @@ export function decideOccurrence( }; case 'privileged-sunday': - if (isAtLeast(sanctoral.rank, 'duplex-majus')) { - // Never displaced, but a sufficiently high feast still gets a nod. - return { winner: temporalWinner, commemorations: [sanctoralCommemoration(sanctoral)] }; - } - // Below duplex-majus, a privileged Sunday wants nothing at all — - // not even the bare commemoration an ordinary Sunday would allow a - // Simplex — so everything here transfers. + // A privileged Sunday wants nothing at all, no matter how high the + // candidate ranks — not even the bare commemoration an ordinary + // Sunday would allow a Simplex, and no exception for duplex-majus+ — + // everything transfers. Live-verified 2026-09-01, three independent + // dates: the Immaculate Conception (Duplex I. classis) transfers off + // Advent II with no commemoration at all (real dates 2024/2030/2041), + // and the Annunciation (also Duplex I. classis) transfers off both + // Palm Sunday and Easter Sunday itself the same way (2029/2035/2040/ + // 2046) — confirmed by direct instruction as the correct behavior, + // correcting an earlier, never-actually-verified "duplex-majus+ + // still gets a nod" guess. (Where a transferred candidate actually + // lands is a separate, still-generic `transferDirectionOf`/next- + // open-day mechanism — the Annunciation's own real rule of jumping + // *past* the whole Easter Octave rather than landing inside it is a + // known follow-on, blocked on the not-yet-built Easter-octave + // mechanism; see TODO.md.) return { winner: temporalWinner, commemorations: [], diff --git a/src/calendar/temporal.ts b/src/calendar/temporal.ts index 51b316a..b0c3786 100644 --- a/src/calendar/temporal.ts +++ b/src/calendar/temporal.ts @@ -202,12 +202,23 @@ export function adventEmberDayOffset(isoDate: string): number | undefined { * the Christmas vigil (Dec 24 can land on a Sunday) — and a Sunday's own * privileged/ordinary status should win in that case regardless, so * Sundays are resolved straight from `bySeason` without consulting the - * overrides at all. + * overrides at all. The one deliberate exception is Easter Sunday itself + * (offset 0): `eastertide`'s own `bySeason` default is `ordinary-sunday` + * (live-verified for the *ordinary* Sundays that follow it — see that + * entry's own comment), but Easter Day needs the stronger + * `privileged-sunday` tier instead (live-verified 2026-09-01: the + * Annunciation, Duplex I. classis, transfers off Easter Day itself in + * years they coincide, the same "transfers, no exception" behavior as + * every other privileged-sunday case) — checked directly here rather + * than via `offsets`, since offsets are never consulted for a Sunday. */ export function resolveTemporalCategory(isoDate: string, season: Season, weekday: Weekday): TemporalCategory { const bySeasonEntry = temporalCategories.bySeason[season]; const base = bySeasonEntry ? (weekday === 'sunday' ? bySeasonEntry.sunday : bySeasonEntry.feria) : 'ordinary-feria'; if (weekday === 'sunday') { + if (season === 'eastertide' && easterOffsetOf(isoDate) === 0) { + return 'privileged-sunday'; + } return base; } diff --git a/src/data/calendar/temporal-categories.yml b/src/data/calendar/temporal-categories.yml index 8e7de18..e7c7dfa 100644 --- a/src/data/calendar/temporal-categories.yml +++ b/src/data/calendar/temporal-categories.yml @@ -48,6 +48,19 @@ # fixability but currently fall to the plain `ordinary-feria` default # instead (see the offsetRanges comment below) — unverified, a real gap, # not a guess dressed up as one. +# +# 2026-09-01 full sweep: every `bySeason` entry now live-verified or +# explicitly noted as not (see each entry's own comment below) — found +# and fixed two real bugs in the process (`eastertide`'s and +# `ascensiontide`'s own `sunday` tiers were each backwards), and a third, +# deeper one in `commemorations.ts` itself (`privileged-sunday`'s +# duplex-majus+ candidates were wrongly given a bare commemoration +# instead of transferring like every other rank there). Every `feria` +# entry in `bySeason` besides the ones with their own verification +# comment is the trivial `ordinary-feria` default (no rank threshold at +# all — any real content wins outright) — not worth a dedicated live +# collision test on top of the hundreds of ordinary weekdays already +# exercising it correctly across this app's whole test suite. bySeason: # Advent's ordinary ferias verified `privileged-feria-minor` during the # December sanctoral pull (see calendar/types.ts's TemporalCategory doc @@ -81,7 +94,20 @@ bySeason: septuagesima: { sunday: privileged-sunday, feria: ordinary-feria } lent: { sunday: privileged-sunday, feria: ordinary-feria } passiontide: { sunday: privileged-sunday, feria: ordinary-feria } - eastertide: { sunday: privileged-sunday, feria: ordinary-feria } + # The ordinary Sundays after Easter (i.e. not Easter Day itself, not + # within its Octave — both handled elsewhere) are `ordinary-sunday`, + # NOT `privileged-sunday` — originally miscoded, live-verified + # 2026-09-01, two independent Duplex-II-classis collisions on "Dominica + # IV Post Pascha" (the Finding of the Holy Cross, 2026-05-03; St. Mark, + # 2027-04-25): both win outright, with the Sunday itself only noted as + # a `Tempora` commemoration underneath — exactly `ordinary-sunday`'s + # Duplex+ rule, the reverse of `privileged-sunday`'s (which would keep + # the Sunday primary and transfer the feast entirely, per the + # Ascensiontide/Advent/Palm-Sunday/Easter-Day evidence above and + # below). Easter Day itself (offset 0) and its Octave (offsets 1-6, + # `privileged-feria-major` via offsetRanges below) are unaffected by + # this — only the ordinary Sundays past the Octave use this default. + eastertide: { sunday: ordinary-sunday, feria: ordinary-feria } # The Sunday within the Octave of Ascension is `privileged-sunday`, not # `ordinary-sunday` — live-verified 2026-09-01: the reference engine # titles it "Dominica infra Octavam Ascensionis ~ Semiduplex Dominica @@ -92,6 +118,11 @@ bySeason: # Matches the same "great octave" pattern as eastertide/pentecost above, # both already `privileged-sunday`. ascensiontide: { sunday: privileged-sunday, feria: ordinary-feria } + # Pentecost Sunday itself — no fixed-date saint collision found/ + # attempted to independently verify this specific entry, but consistent + # with the confirmed "great octave Sundays are privileged-sunday" + # pattern (Easter Day, Ascension's own octave Sunday) — Pentecost + # outranks both. pentecost: { sunday: privileged-sunday, feria: ordinary-feria } trinitytide: { sunday: ordinary-sunday, feria: ordinary-feria } # Corpus Christi/Sacred Heart are themselves "feasts of the Lord" that @@ -99,7 +130,14 @@ bySeason: # privileged-feria-major (rather than injecting a separate synthetic # FeastClass) since with the small sanctoral calendar this app has, a # real clash is unlikely and the practical effect (temporal wins) is the - # same either way. + # same either way. Not independently live-verified (no fixed-date saint + # collision found/attempted), but same "feast of the Lord" reasoning + # already confirmed for Ash Wednesday/Holy Week/the Easter Octave. + # `sunday` is checked here for shape-consistency with every other + # season entry, but genuinely unreachable in practice — per + # data/calendar/easter-offsets.yml's `days:` table, both are single + # fixed weekdays (Corpus Christi always a Thursday, Sacred Heart always + # the following Friday), never a Sunday. corpus-christi: { sunday: ordinary-sunday, feria: privileged-feria-major } sacred-heart: { sunday: ordinary-sunday, feria: privileged-feria-major } @@ -108,7 +146,7 @@ offsets: -39: privileged-feria # Lent Ember Wednesday (Wed after 1st Sunday of Lent) — verified: Duplex wins outright here -37: privileged-feria # Lent Ember Friday -36: privileged-feria # Lent Ember Saturday — verified: Duplex wins outright here (St. Gregory the Great) - 48: privileged-feria-major # Vigil of Pentecost — unverified, defaulted to the stricter tier + 48: privileged-feria-major # Vigil of Pentecost — no live saint-collision test found/attempted (rare by construction), but corroborated 2026-09-01 by its own formal rank in the reference source (Sancti/Pentecost Vigil file's own [Rank]: "Semiduplex I classis" — a genuinely first-class day, consistent with the stricter tier) offsetRanges: - { fromOffset: -6, toOffset: -1, category: privileged-feria-major } # ferias of Holy Week @@ -129,4 +167,4 @@ offsetRanges: # existing one, not introduced by this change. fixedDates: - "12-24": privileged-feria-major # Vigil of Christmas — unverified, defaulted to the stricter tier + "12-24": privileged-feria-major # Vigil of Christmas — no live saint-collision test found/attempted, but corroborated 2026-09-01 by its own formal rank in the reference source (Sancti/12-24.txt's own [Rank]: "Duplex I classis", consistent with the stricter tier) diff --git a/tests/calendar/april-sanctoral.test.ts b/tests/calendar/april-sanctoral.test.ts index 9932405..9c05dbf 100644 --- a/tests/calendar/april-sanctoral.test.ts +++ b/tests/calendar/april-sanctoral.test.ts @@ -34,27 +34,30 @@ describe('April sanctoral pull (first pass)', () => { ]); }); - it('a privileged Eastertide Sunday bumps even St. Robert (plain Duplex, not Duplex majus) to transfer forward', () => { - // 2029: Apr 29 is a privileged Sunday in Eastertide, so Robert can't - // win or be commemorated there — he transfers to Monday and wins the - // collision against St. Peter Martyr instead. + it('an ordinary Eastertide Sunday (not Easter Day, not within its Octave) still lets St. Robert (plain Duplex) win outright, same as any weekday', () => { + // 2029: Apr 29 is an ordinary (not privileged) Sunday in Eastertide — + // live-verified 2026-09-01 (`eastertide`'s own `bySeason` entry, see + // data/calendar/temporal-categories.yml): "S. Roberti Abbatis ~ + // Duplex" wins outright there, same as data/calendar/temporal- + // categories.yml's `ordinary-sunday` rule for any other season, with + // the Sunday itself only noted as a `Scriptura` line, not primary. const sunday = resolveDay('2029-04-29'); - expect(sunday.winner).toEqual({ kind: 'temporal', id: 'easter-5' }); + expect(sunday.winner).toEqual({ kind: 'sanctoral', id: 'st-robert', name: 'St. Robert, Abbot', nameLa: 'Sanctus Robertus, Abbas', rank: 'duplex' }); expect(sunday.commemorations).toEqual([ + { kind: 'temporal', id: 'easter-5' }, { kind: 'sanctoral', id: 'st-catherine-of-siena', name: 'St. Catherine of Siena, Virgin', nameLa: 'Sancta Catharina Senensis, Virgo', rank: 'simplex' }, ]); + // Apr 30 resolves St. Peter Martyr cleanly on his own day — no + // transferred-Robert collision, since Robert already won on the 29th. const monday = resolveDay('2029-04-30'); expect(monday.winner).toEqual({ kind: 'sanctoral', - id: 'st-robert', - name: 'St. Robert, Abbot', - nameLa: 'Sanctus Robertus, Abbas', - rank: 'duplex', - transferredFrom: '2029-04-29', + id: 'st-peter-martyr', + name: 'St. Peter Martyr, Martyr', + nameLa: 'Sanctus Petrus Martyr, Martyr', + rank: 'semiduplex', }); - expect(monday.commemorations).toEqual([ - { kind: 'sanctoral', id: 'st-peter-martyr', name: 'St. Peter Martyr, Martyr', nameLa: 'Sanctus Petrus Martyr, Martyr', rank: 'semiduplex' }, - ]); + expect(monday.commemorations).toEqual([]); }); }); diff --git a/tests/calendar/commemorations.test.ts b/tests/calendar/commemorations.test.ts index ac6373a..07deb15 100644 --- a/tests/calendar/commemorations.test.ts +++ b/tests/calendar/commemorations.test.ts @@ -141,18 +141,16 @@ describe('decideOccurrence — ordinary-sunday', () => { }); describe('decideOccurrence — privileged-sunday', () => { - it('is never displaced; duplex-majus and up are commemorated', () => { - for (const rank of ['duplex-majus', 'duplex-2-classis', 'duplex-1-classis'] as const) { + it('is never displaced, and never gives even a bare commemoration to any rank — everything transfers forward', () => { + // Live-verified 2026-09-01 (see data/calendar/temporal-categories.yml + // and commemorations.ts's own `privileged-sunday` case comment): + // even a Duplex I. classis feast (the Immaculate Conception on Advent + // II, the Annunciation on Palm/Easter Sunday) transfers with no + // commemoration at all — corrects an earlier, never-actually-verified + // "duplex-majus+ still gets a nod" guess. + for (const rank of ['duplex-majus', 'duplex-2-classis', 'duplex-1-classis', 'duplex', 'semiduplex', 'simplex'] as const) { const result = decideOccurrence('privileged-sunday', 'advent-1', saint(rank)); expect(result.winner).toEqual({ kind: 'temporal', id: 'advent-1' }); - expect(result.commemorations).toEqual([{ kind: 'sanctoral', id: 'x', name: 'St. Ereden', rank }]); - expect(result.transfer).toBeUndefined(); - } - }); - - it('duplex, semiduplex, and simplex all transfer forward — no bare commemoration here', () => { - for (const rank of ['duplex', 'semiduplex', 'simplex'] as const) { - const result = decideOccurrence('privileged-sunday', 'advent-1', saint(rank)); expect(result.commemorations).toEqual([]); expect(result.transfer).toEqual({ candidate: saint(rank), direction: 'forward' }); } diff --git a/tests/calendar/day-label.test.ts b/tests/calendar/day-label.test.ts index c8c97eb..3247130 100644 --- a/tests/calendar/day-label.test.ts +++ b/tests/calendar/day-label.test.ts @@ -66,21 +66,31 @@ describe('getDayLabel — ordinal temporal label', () => { }); it("Advent's own anchor Sunday is already week 1, not a separate anchor-week case", () => { - // 2025-11-30 is also St. Andrew's own day (Duplex II. classis) — since - // the November sanctoral pull, he's correctly commemorated alongside - // Advent I rather than simply absent (confirmed against the live - // reference engine, which shows the same pairing), so the label - // reflects both, winner (Advent I, so privileged nothing can displace - // it) first, commemorated saint after. - expect(getDayLabel(resolveDay('2025-11-30')).en).toBe('The 1st Sunday of Advent (Semiduplex) — St. Andrew, Apostle'); + // 2025-11-30 is also St. Andrew's own day (Duplex II. classis) — a + // privileged Sunday transfers *everything*, no rank exception + // (live-verified 2026-09-01, correcting an earlier, inaccurate claim + // that he was commemorated in place: the real Monastic 1617 engine + // shows "Transfer: S. Andreæ Apostoli", not a commemoration), so the + // label shows him as transferred away rather than paired alongside + // Advent I. + expect(getDayLabel(resolveDay('2025-11-30')).en).toBe('The 1st Sunday of Advent (Semiduplex) — St. Andrew, Apostle (transferred away)'); + // Dec 1 is where Andrew's own transfer actually lands (the next open + // day, `privileged-feria-minor`'s Semiduplex+ threshold easily clears + // for a Duplex II. classis) — live-verified 2026-09-01, the real + // Monastic 1617 engine shows "S. Andreæ Apostoli ~ Duplex II. classis" + // there outright, "Tempora: Feria II infra Hebdomadam I Adventus" + // underneath, matching this. + expect(getDayLabel(resolveDay('2025-12-01')).en).toBe('St. Andrew, Apostle (Duplex II Class, transferred) — In the 1st week of Advent'); + // Dec 4 (St. Barbara, merely commemorated, not high-ranked enough to + // win outright) is a clean example of the season-ordinal label itself. // Advent drops the redundant leading weekday word now that the header // always shows the weekday on its own (see temporalLabel's // `dropWeekdayPrefix`). - expect(getDayLabel(resolveDay('2025-12-01')).en).toBe('In the 1st week of Advent (Feria)'); + expect(getDayLabel(resolveDay('2025-12-04')).en).toBe('In the 1st week of Advent (Feria) — St. Barbara, Virgin and Martyr'); // Latin: same weekday-drop, and the season-ordinal genitive // construction ("Hebdomada prima Adventus") needs no extra linking // word — 4th-declension "Adventus" has the same genitive form. - expect(getDayLabel(resolveDay('2025-12-01')).la).toBe('In hebdomada prima Adventus (Feria)'); + expect(getDayLabel(resolveDay('2025-12-04')).la).toBe('In hebdomada prima Adventus (Feria) — Sancta Barbara, Virgo et Martyr'); }); it('falls back to weekday + season name for seasons with no ordinal convention modeled', () => { diff --git a/tests/hours/compline.test.ts b/tests/hours/compline.test.ts index f5c1649..a660605 100644 --- a/tests/hours/compline.test.ts +++ b/tests/hours/compline.test.ts @@ -104,17 +104,21 @@ describe('resolveOrdo("compline", ...)', () => { it('anticipates Advent I: the Saturday evening before switches to the Alma Redemptoris Mater and shows the anticipated day label', () => { // Nov 30, 2025 is Advent I Sunday -- also St. Andrew's own day - // (Duplex II. classis), correctly commemorated alongside it since the - // November sanctoral pull (see tests/calendar/day-label.test.ts). This - // evening also anticipates Advent I from Nov 29, itself the Vigil of - // St. Andrew -- but the Vigil isn't also shown alongside his own - // feast (calendar/vespers.ts's own isVigilOfTomorrow check, keyed off - // each Vigil's explicit `vigilOf` field): showing both would just be - // redundant, the same feast named twice. + // (Duplex II. classis), but a privileged Sunday transfers him + // entirely rather than commemorating him in place (live-verified + // 2026-09-01, see tests/calendar/day-label.test.ts). This evening + // also anticipates Advent I from Nov 29, itself the Vigil of St. + // Andrew -- calendar/vespers.ts's own isVigilOfTomorrow check only + // suppresses the Vigil's own commemoration when tomorrow's page + // *also* shows St. Andrew (which would be redundant); since he no + // longer does (he's transferred away, not commemorated), both pieces + // of information are genuinely distinct and both show. const eve = resolveOrdo('compline', '2025-11-29'); const last = eve.parts[eve.parts.length - 1]; expect(last?.kind === 'preces' ? last.label : undefined).toBe('Alma Redemptoris Mater'); - expect(eve.dayLabel?.en).toBe('The 1st Sunday of Advent (Semiduplex) — St. Andrew, Apostle'); + expect(eve.dayLabel?.en).toBe( + 'The 1st Sunday of Advent (Semiduplex) — Vigil of St. Andrew (of today) — St. Andrew, Apostle (transferred away)', + ); const dayBefore = resolveOrdo('compline', '2025-11-28'); const lastBefore = dayBefore.parts[dayBefore.parts.length - 1]; diff --git a/tests/hours/lauds.test.ts b/tests/hours/lauds.test.ts index 6f6d9f3..7558e41 100644 --- a/tests/hours/lauds.test.ts +++ b/tests/hours/lauds.test.ts @@ -565,18 +565,20 @@ describe('resolveOrdo("lauds", ...)', () => { }); it('resolves both the winners collect and a commemorated saints collect on a day with a real commemoration', () => { - // 2025-11-30: Advent I (the winner) with St. Andrew, Duplex II. classis, - // commemorated alongside it (see tests/calendar/day-label.test.ts) -- - // he has only a bare collect authored (no st-andrew-commemoration.yml - // Ant+V/R bundle yet), so this renders as a labeled 'preces' block - // (see resolve-common.ts's sanctoralCommemorationPart), not a second - // unlabeled 'prayer' the way it used to. - const ordo = resolveOrdo('lauds', '2025-11-30'); + // 2029-01-14: post-Epiphany II (the winner, `ordinary-sunday`) with + // St. Felix Presbyter, Simplex, commemorated alongside it — live- + // verified 2026-09-01. (Not 2025-11-30/St. Andrew as this test used + // to: a privileged Sunday transfers *everything*, no rank exception + // — Andrew doesn't get a bare commemoration there at all, see + // tests/calendar/day-label.test.ts. `ordinary-sunday`'s own Simplex + // branch is the real case that still commemorates a saint in place.) + const ordo = resolveOrdo('lauds', '2029-01-14'); const collects = ordo.parts.filter((p) => p.kind === 'prayer'); expect(collects.length).toBe(1); - const andrewCommemoration = ordo.parts.find((p) => p.kind === 'preces' && p.label?.includes('Andrew')); - expect(andrewCommemoration?.kind === 'preces' ? andrewCommemoration.text.text.en : undefined).toContain( - 'Andrew', + const felixCommemoration = ordo.parts.find((p) => p.kind === 'preces' && p.label?.includes('Felix')); + expect(felixCommemoration).toBeDefined(); + expect(felixCommemoration?.kind === 'preces' ? felixCommemoration.text.text.en : undefined).toContain( + 'palm tree', ); }); diff --git a/tests/hours/matins.test.ts b/tests/hours/matins.test.ts index 1ba3b27..cfa0642 100644 --- a/tests/hours/matins.test.ts +++ b/tests/hours/matins.test.ts @@ -718,7 +718,7 @@ describe('resolveOrdo("matins", ...) rest-of-year temporal nocturn-readings swee ['2026-04-19', 'easter-3'], ['2026-04-27', 'easter-4'], ['2026-05-04', 'easter-5'], - ['2026-05-11', 'easter-6'], + ['2026-05-10', 'easter-6 (the real Sunday — not 2026-05-11: since the eastertide-Sunday precedence fix (2026-09-01), St. Antoninus, Duplex, now correctly wins outright on his own day, May 10, rather than transferring onto Monday, so easter-6\'s own pooled readings show up there commemorated, not on the 11th)'], ['2026-05-18', 'sunday-after-ascension'], ['2026-04-05', 'easter-sunday'], ['2026-05-24', 'pentecost-sunday'],