diff options
| -rw-r--r-- | lib/rites/rite_of/temporal_of.ml | 28 | ||||
| -rw-r--r-- | lib/rites/rite_of/temporal_of.mli | 11 | ||||
| -rw-r--r-- | test/test_precedence_of.ml | 36 | ||||
| -rw-r--r-- | test/test_temporal_of.ml | 23 |
4 files changed, 85 insertions, 13 deletions
diff --git a/lib/rites/rite_of/temporal_of.ml b/lib/rites/rite_of/temporal_of.ml index 9aa898e..e375350 100644 --- a/lib/rites/rite_of/temporal_of.ml +++ b/lib/rites/rite_of/temporal_of.ml @@ -238,7 +238,33 @@ let named d = let easter = Computus.gregorian_easter y in let off n = Date.add_days easter n in let m = Date.month d and dd = Date.day d in - if m = 12 && dd = 24 then Some (Advent, "of-nativity-vigil", Colour.White, Sollemnitas) + if m = 12 && dd = 24 && Date.weekday d <> Date.Sun then + Some (Advent, "of-nativity-vigil", Colour.White, Sollemnitas) + (* NOT unconditional. Tabula I.2 ("Dominicae Adventus, Quadragesimae et + Paschae") outranks Tabula I.3 (solemnities generally, where the Vigil + Mass of the Nativity itself bands, per Precedence_of.band's own entry-3 + branch) -- Normae n. 5 states it directly for exactly this class of + day: a Sunday of Advent/Lent/Easter yields to nothing but a still + higher-banked day. The Fourth Sunday of Advent is one of those + privileged Sundays every time 24 December falls on one. + + The Vigil Mass is an evening Mass of the FOLLOWING solemnity (the + Nativity, 25 December), not an office belonging to 24 December's own + civil day -- the identical granularity reasoning + Precedence_of.band's own entry-1 comment already applies to Holy + Thursday (the Triduum opens with an evening Mass inside Holy + Thursday's civil day, so the day itself stays at entry 2, not entry + 1) and that data/of/expected-divergences-litcal.sexp's L1 entry + applies on the season axis. At colitur's one-office-per-civil-day + granularity, only one identity can hold 24 December, and on a Sunday + that identity is the Fourth Sunday of Advent, not the Vigil -- so + [named] must return [None] here and let [temporal]'s dispatch fall + through to [sunday_slug], exactly as it already does for every other + Sunday [named] does not claim. + + Every non-Sunday 24 December is unaffected: the Vigil still wins + there, as a plain late-Advent feria (Tabula II.9) is never privileged + against it. *) else if m = 12 && dd = 25 then Some (Christmas, "of-nativity", Colour.White, Sollemnitas) else if m = 1 && dd = 1 then Some (Christmas, "of-mary-mother-of-god", Colour.White, Sollemnitas) else if m = 1 && dd = 6 then Some (Christmas, "of-epiphany", Colour.White, Sollemnitas) diff --git a/lib/rites/rite_of/temporal_of.mli b/lib/rites/rite_of/temporal_of.mli index 982ff05..d2acadd 100644 --- a/lib/rites/rite_of/temporal_of.mli +++ b/lib/rites/rite_of/temporal_of.mli @@ -103,7 +103,16 @@ val christ_the_king : int -> Date.t threading extra state through every other branch too -- the exact reason EF's own [named] excludes its structurally identical Holy Family/Holy Name. {!temporal} applies all three as its own targeted - dispatch instead. *) + dispatch instead. + + 24 December is ALSO conditional, not unconditional like the rest of this + function's fixed dates: it yields [of-nativity-vigil] only when that date + is not itself a Sunday. On a Sunday, [None] is returned so {!temporal}'s + dispatch falls through to {!sunday_slug}'s own [of-advent-sunday-4] -- + Tabula I.2/Normae n. 5's Sundays of Advent outrank the Vigil (Tabula + I.3), the same evening-Mass-inside-the-civil-day reasoning already + applied to Holy Thursday (see [named]'s own implementation comment for + the full argument). *) val named : Date.t -> (Vocab_of.season * string * Colour.t * Vocab_of.rank) option (** Week within the season, 1-indexed, Sunday-aligned (constant across a diff --git a/test/test_precedence_of.ml b/test/test_precedence_of.ml index 4de9f9a..610cbfb 100644 --- a/test/test_precedence_of.ml +++ b/test/test_precedence_of.ml @@ -162,17 +162,31 @@ let part2_cases = entry 3. The pinned assertion above is still correct for the Thursday it names; only the earlier "band 30" framing read as unconditional, which it is not. - There is a real, KNOWN, UNFIXED Phase 1 defect behind this: [named] - (temporal_of.ml) claims 24 December unconditionally and is matched - BEFORE [sunday_slug] in [temporal]'s dispatch, so on a 24-December - Sunday the Fourth Sunday of Advent gets NO office at all -- it is - silently replaced by [of-nativity-vigil]. 2028-12-24 and 2034-12-24 - both fall inside the litcal fixture window, and that layer cannot see - the gap: it compares season and Ordinary-Time week only, and colitur - still says "advent" on that date either way. NOT fixed in this wave - (final review Important #4, ledger ruling R8) -- it changes Phase 1 - behaviour, needs its own tests, and needs the litcal layer re-run. - Carried as the first item of the next task. *) + RESOLVED (task R8, 2026-08-25): the Phase 1 defect this paragraph used + to describe -- [named] (temporal_of.ml) claiming 24 December + unconditionally, matched BEFORE [sunday_slug] in [temporal]'s + dispatch, so a 24-December Sunday silently lost the Fourth Sunday of + Advent to [of-nativity-vigil] -- is fixed. [named] now returns [None] + for 24 December when that date is itself a Sunday, citing Tabula + I.2/Normae n. 5 and the identical Holy Thursday granularity argument + (b) above already makes; [temporal]'s dispatch then falls through to + [sunday_slug] exactly as it does for every other Sunday [named] does + not claim, landing on [of-advent-sunday-4]. Paragraph (d) above + already anticipated the RIGHT band (20, via [is_privileged_sunday]) + for that case; this fix is what makes that band actually reachable + from a real [temporal] call rather than only from this row's own + hand-built candidate. Confirmed on both 2028-12-24 and 2034-12-24 + (test_temporal_of.ml, "nativity vigil yields to Advent Sunday IV"): + [named] claims nothing, [temporal] resolves to [of-advent-sunday-4], + and the non-Sunday case (2026-12-24 here) is unchanged. The litcal + layer was re-run: no allow-list count moved (L1's 36, the 1876 + witnessed Ordinary Time weeks, and the 859 unwitnessed count are all + unchanged), because that layer compares season and Ordinary-Time week + only and both readings of 24 December are "advent" either way -- the + exact blind spot this same paragraph named above. This row's own + pinned assertion (a hand-built candidate, Thursday 2026-12-24, band + 30) needed no change: it was never wrong, only the claim that no test + anywhere exercised the Sunday case. *) ( "entry 3, not 9: the Nativity Vigil is a solemnity, though 24 December \ is also a late-Advent feria", ctx ~iso:"2026-12-24" ~season:Vocab_of.Advent, diff --git a/test/test_temporal_of.ml b/test/test_temporal_of.ml index 7560413..1ccd098 100644 --- a/test/test_temporal_of.ml +++ b/test/test_temporal_of.ml @@ -230,6 +230,28 @@ let test_ferial_slugs () = Alcotest.(check string) "ordinary weekday" "of-ordinary-time-2-monday" (slug_of (d 2026 1 19)); Alcotest.(check string) "lent weekday" "of-lent-6-monday" (slug_of (d 2026 3 30)) +(* R8 fix: a Sunday 24 December must yield the Fourth Sunday of Advent, not + the Vigil -- Tabula I.2/Normae n. 5, and temporal_of.ml's own [named] + comment for the full argument (the same civil-day-granularity reasoning + already applied to Holy Thursday). 2028-12-24 and 2034-12-24 are the two + such Sundays inside the litcal fixture window (2023-12-03..2035-12-01); + 2026-12-24, a Thursday, is the non-Sunday control. *) +let test_nativity_vigil_yields_to_advent_sunday () = + List.iter + (fun (y, label) -> + let dt = d y 12 24 in + Alcotest.(check bool) (label ^ ": 24 Dec is a Sunday") true (D.weekday dt = D.Sun); + Alcotest.(check string) (label ^ ": named claims nothing") "<none>" (named_slug dt); + Alcotest.(check string) (label ^ ": temporal resolves to Advent IV") "of-advent-sunday-4" (slug_of dt); + Alcotest.(check string) (label ^ ": season is still advent") "advent" (season_str dt); + Alcotest.(check (option int)) (label ^ ": week 4") (Some 4) (T.week dt)) + [ (2028, "2028"); (2034, "2034") ]; + (* Non-Sunday 24 December: unaffected, the Vigil still wins. *) + let thu = d 2026 12 24 in + Alcotest.(check bool) "2026: 24 Dec is a Thursday, not a Sunday" true (D.weekday thu <> D.Sun); + Alcotest.(check string) "2026: named still claims the vigil" "of-nativity-vigil" (named_slug thu); + Alcotest.(check string) "2026: temporal still resolves to the vigil" "of-nativity-vigil" (slug_of thu) + let test_colours () = let colour_of dt = (T.temporal dt).Colitur_kernel.Temporal.office.Colitur_kernel.Celebration.colour in Alcotest.(check string) "Good Friday is red" "red" (Colitur_kernel.Colour.to_string (colour_of (d 2026 4 3))); @@ -387,6 +409,7 @@ let suite = Alcotest.test_case "ordinary time resumption" `Quick test_ordinary_time_resumption; Alcotest.test_case "sunday slugs" `Quick test_sunday_slugs; Alcotest.test_case "ferial slugs" `Quick test_ferial_slugs; + Alcotest.test_case "nativity vigil yields to Advent Sunday IV" `Quick test_nativity_vigil_yields_to_advent_sunday; Alcotest.test_case "colours" `Quick test_colours; Alcotest.test_case "domain edges do not raise" `Quick test_domain_edges_do_not_raise; Alcotest.test_case "exhaustive domain sweep" `Slow test_exhaustive_domain_sweep ] |
