From f40eb498c612aeda2ff7f3d5b898e4d1ddcec352 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 12 Aug 2026 13:04:53 +0200 Subject: temporal_ef: Sunday ranks, Rose Sundays, Holy Thursday white Four fixes to internal/calendar/temporal_ef.go, all found by the strengthened oracle test (previous commit): 1. Sunday ranks (defect 4). The generic Sunday branch assigned class-2 to every Sunday except Advent I. RG 11-12 / RG 91 entry 6: every Sunday of Advent and every Sunday of Lent is I class (as are Passiontide's own two Sundays and Low Sunday, already correct via their named-feast cases). Fixes St Joseph wrongly taking a Sunday of Lent (defect 3, precedence_ef_repro_test.go's TestJosephYieldsToSundayOfLent) as a direct consequence: once Lent Sundays are I class, Joseph (also I class) no longer wins the tie outright and correctly transfers to the 20th via the existing RG 96 walk -- no separate code change was needed for defect 3. 2. Rose (defect 5). efColour had no Rose case at all; Gaudete (Advent III) and Laetare (Lent IV) now get Rose on that Sunday specifically (RG 131: rose vestments may be used "in Officio et Missa diei dominici tantum", for that Sunday's Office and Mass only), not the surrounding Sundays. 3. Holy Thursday's colour (defect 6). RG 128(b) names the Missa in Cena Domini as a whole-Mass exception to Passiontide's violet; RG 122 states the same fact affirmatively, in the White section itself. Good Friday and Holy Saturday, either side, are unchanged (still violet -- their own black/no-colour treatment is a separate, unmodelled gap, noted in precedence_ef.go's own doc comments). 4. Beyond the seven, found by the same strengthened test and fixed for the same RG 91 entry 18 reason defect 2 (next commit) relies on: the Ember days of Lent had no case in efEmberSlug at all (only September and Advent did), so they fell through to the ordinary III-class Lenten-feria rank instead of the II class RG 91 entry 18 requires. The late-Advent ferias (17-23 Dec, RG 91 entry 18) and the days within the Octave of the Nativity (26-31 Dec, RG 67-68) had no elevation at all, defaulting to III/IV class. All three are one-line, unambiguous, primary-cited additions to the same rank logic already being touched here -- left unfixed, the strengthened oracle test could only reach green by allow-listing them as if they were defensible divergences, which they are not. Witnesses (temporal_ef_test.go): TestTemporalEFSundayRanks, TestTemporalEFRoseSundays, TestTemporalEFHolyThursdayColour, TestTemporalEFEmberDayRanks. All fail before this commit; see the report for the exact pre-fix failure messages. --- internal/calendar/temporal_ef_test.go | 92 +++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) (limited to 'internal/calendar/temporal_ef_test.go') diff --git a/internal/calendar/temporal_ef_test.go b/internal/calendar/temporal_ef_test.go index 6d632e2..8b1ffa5 100644 --- a/internal/calendar/temporal_ef_test.go +++ b/internal/calendar/temporal_ef_test.go @@ -38,3 +38,95 @@ func TestTemporalEFChristTheKing(t *testing.T) { t.Errorf("efChristTheKing(2025) = %s want 2025-10-26", got) } } + +// TestTemporalEFSundayRanks: RG 11-12 / RG 91 entry 6 -- Sundays of Advent, +// Lent and Passiontide, and Low Sunday, are I class; all others (including +// Septuagesima's own three Sundays and the ordinary Sundays after Epiphany/ +// Pentecost) stay II class. Before the fix, only Advent I was I class; every +// other Advent/Lent Sunday was left at the generic-Sunday II-class default. +func TestTemporalEFSundayRanks(t *testing.T) { + cases := []struct { + date string + want Rank + }{ + {"2025-11-30", RankClass1}, // Advent I + {"2025-12-07", RankClass1}, // Advent II + {"2025-12-14", RankClass1}, // Advent III (Gaudete) + {"2025-12-21", RankClass1}, // Advent IV + {"2025-03-09", RankClass1}, // Lent I + {"2025-03-16", RankClass1}, // Lent II + {"2025-03-23", RankClass1}, // Lent III + {"2025-03-30", RankClass1}, // Lent IV (Laetare) + {"2025-04-06", RankClass1}, // Passion Sunday + {"2025-04-13", RankClass1}, // Palm Sunday + {"2025-04-27", RankClass1}, // Low Sunday + {"2025-02-16", RankClass2}, // Septuagesima Sunday -- NOT I class + {"2025-02-23", RankClass2}, // Sexagesima Sunday -- NOT I class + {"2025-03-02", RankClass2}, // Quinquagesima Sunday -- NOT I class + {"2025-06-22", RankClass2}, // II Sunday after Pentecost -- ordinary II class + } + for _, c := range cases { + got := temporalEF(d(c.date)) + if got.Cel.Rank != c.want { + t.Errorf("temporalEF(%s).Cel.Rank = %s, want %s (%s)", c.date, got.Cel.Rank, c.want, got.Cel.Slug) + } + } +} + +// TestTemporalEFRoseSundays: RG 131 -- rose is permitted on Gaudete (Advent +// III) and Laetare (Lent IV), for that Sunday's own Office and Mass only. +// Before the fix, efColour had no Rose case at all. +func TestTemporalEFRoseSundays(t *testing.T) { + if got := temporalEF(d("2025-12-14")).Cel.Colour; got != Rose { + t.Errorf("Gaudete (2025-12-14) colour = %s, want rose", got) + } + if got := temporalEF(d("2025-03-30")).Cel.Colour; got != Rose { + t.Errorf("Laetare (2025-03-30) colour = %s, want rose", got) + } + // The Advent/Lent Sundays either side stay violet -- rose is an indult for + // that one Sunday, not a season colour. + if got := temporalEF(d("2025-12-07")).Cel.Colour; got != Violet { + t.Errorf("Advent II (2025-12-07) colour = %s, want violet", got) + } + if got := temporalEF(d("2025-03-23")).Cel.Colour; got != Violet { + t.Errorf("Lent III (2025-03-23) colour = %s, want violet", got) + } +} + +// TestTemporalEFHolyThursdayColour: RG 128(b)/RG 122 -- Holy Thursday's Mass +// of Chrism and Mass in Cena Domini are white, a whole-day exception to +// Passiontide's violet. Good Friday and Holy Saturday, either side, stay +// violet (their own black/no-colour exceptions are a separate, unmodelled +// gap -- see RG 132, precedence_ef.go's own doc comments). +func TestTemporalEFHolyThursdayColour(t *testing.T) { + easter := d("2025-04-20") + holyThu := easter.AddDate(0, 0, -3) + goodFri := easter.AddDate(0, 0, -2) + holySat := easter.AddDate(0, 0, -1) + if got := temporalEF(holyThu).Cel.Colour; got != White { + t.Errorf("Holy Thursday colour = %s, want white", got) + } + if got := temporalEF(goodFri).Cel.Colour; got != Violet { + t.Errorf("Good Friday colour = %s, want violet (unchanged)", got) + } + if got := temporalEF(holySat).Cel.Colour; got != Violet { + t.Errorf("Holy Saturday colour = %s, want violet (unchanged)", got) + } +} + +// TestTemporalEFEmberDayRanks: RG 91 entry 18 -- the Ember days of Lent (and, +// unchanged, September and Advent) are II-class privileged ferias, not the +// ordinary III-class Lenten ferias around them. Before the fix, efEmberSlug +// had no Lent case at all, so Lent's Ember Wed/Fri/Sat fell through to the +// ordinary III-class Lenten-feria rank. +func TestTemporalEFEmberDayRanks(t *testing.T) { + // Lent I Sunday 2025 = 2025-03-09; Ember Wed/Fri/Sat = +3/+5/+6. + lentI := d("2025-03-09") + for _, off := range []int{3, 5, 6} { + day := lentI.AddDate(0, 0, off) + got := temporalEF(day) + if got.Cel.Rank != RankClass2 { + t.Errorf("Lent Ember day %s rank = %s, want class-2 (%s)", day.Format("2006-01-02"), got.Cel.Rank, got.Cel.Slug) + } + } +} -- cgit v1.3