summaryrefslogtreecommitdiff
path: root/test/test_rite_of.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 23:45:16 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 23:45:16 +0200
commit9ebb06983b7a26db5564302253f2551dfbcf834e (patch)
treef73de5c193a13239258d062ca5f4caf64ba64dbe /test/test_rite_of.ml
parent2f6d25aff88b4c76c61e36889f1c017b3cc8faee (diff)
downloadcolitur-9ebb06983b7a26db5564302253f2551dfbcf834e.tar.gz
colitur-9ebb06983b7a26db5564302253f2551dfbcf834e.zip
fix(of): dispatch Holy Family's Normae n.35(a) fallback (W2)
temporal_of.ml's temporal only ever reached holy_family's own correct 26-31 December / 30 December fallback logic through sunday_slug, which returns None immediately for a non-Sunday date. In a year 25 December is itself a Sunday (26-31 December then holding no Sunday of its own), the feast vanished entirely and fell through to an ordinary Christmas ferial slug -- confirmed on 2022, 2033, 2039, 2044, 2050 (and roughly 1583..9999 domain-wide, one year in seven). temporal's dispatch now consults holy_family directly, independent of weekday, between the sunday_slug and christmas_feria_slug branches, carrying the identical identity the Sunday case already builds (subject Lord, holy_family_names, rank Festum). holy_family and anchors were already correct and needed no change. Added a direct example-based test for the fallback across five affected years plus a control for the unaffected Sunday case, and a domain-wide property (Holy Family is observed in every liturgical year 1583-9999) folded into both the 200-sample QCheck run and the exhaustive sweep -- the property that would have caught this directly. Un-pinned the now-fixed behaviour everywhere it was recorded as known-wrong: test_rite_of.ml's own 1583 pin (rewritten to assert the fix), test_validate_of.ml's own independent exhaustive-sweep counter and landmark-year filter (found via make check, not the initial survey), and data/of/expected-divergences-litcal.sexp's L2/L3 allow-list entries against the litcal oracle (closed and removed, with a dedicated regression test replacing the allow-list's own silence).
Diffstat (limited to 'test/test_rite_of.ml')
-rw-r--r--test/test_rite_of.ml136
1 files changed, 78 insertions, 58 deletions
diff --git a/test/test_rite_of.ml b/test/test_rite_of.ml
index a7d3237..42c9c98 100644
--- a/test/test_rite_of.ml
+++ b/test/test_rite_of.ml
@@ -109,46 +109,49 @@ let contains ~substring s =
let is_known_nativity_gap (f : Val.failure) =
(f.Val.check = "citations-unresolved" || f.Val.check = "formulary") && ends_with ~suffix:"12-25" f.Val.date
-(* A SECOND, NEWLY-FOUND gap this task's own wiring surfaced -- [rite_of] was
- never previously wired into a real {!Colitur_kernel.Rite.t}, so
- [Validate.run]'s ["anchor"] check has never before run [Temporal_of
- .anchors] against [Temporal_of.temporal] for real. Normae n. 35(a)'s own
- text is "Dominica infra octavam Nativitatis, VEL, EA DEFICIENTE, die 30
- decembris" -- the Holy Family fallback is a FIXED-DATE fallback (30
- December, whatever weekday it falls on that year), confirmed by
- {!Temporal_of.holy_family}'s own [None -> mk y 12 30] branch and its own
- .mli citation ("this 6-day window CAN be [empty of a Sunday] -- confirmed
- by the fallback clause's own existence"). But {!Temporal_of.temporal}
- only ever TESTS [same d (holy_family y)] inside its [sunday_slug d]
- dispatch arm -- i.e. only when [d] genuinely IS a Sunday -- so in a year
- whose 26-31 December window has NO Sunday (equivalently: 25 December,
- Christmas Day, is itself a Sunday -- a 6-day window starting the day
- after a Sunday omits Sunday from every other position), the fallback
- date is computed correctly by [holy_family]/[anchors] but [temporal]
- itself silently falls through to an ordinary ferial slug instead
- (["of-christmas-0-friday"] et al.) -- exactly the "generic day slug
- masking a real named feast" shape CLAUDE.md already records EF's own
- Holy Family/Holy Name gaps as, before they were fixed there. Not rare:
- this fires whenever Christmas Day is a Sunday, roughly one year in
- seven (1583, 2005, 2011, 2016, 2022, 2033, 2039, 2044, 2050 all
- independently confirmed via Python's own proleptic-Gregorian
- [datetime]). OUT OF THIS TASK'S SCOPE to fix -- temporal_of.ml's own
- rubric logic is Task 1's deliverable, not Task 5's, and the task brief
- models exactly this "pin the known-wrong behaviour, do not fix it here"
- treatment for a different, already-known gap (Normae n.56(f), St
- Joseph/Palm Sunday) -- so the same discipline is applied to this
- newly-found one rather than silently working around it or fixing rite
- logic this task was not chartered to touch. Reported in this task's own
- report as a concern. *)
+(* CLOSED (W2, CLAUDE.md; fixed in temporal_of.ml). This paragraph used to
+ describe a SECOND, NEWLY-FOUND gap this task's own wiring surfaced --
+ [rite_of] was never previously wired into a real
+ {!Colitur_kernel.Rite.t}, so [Validate.run]'s ["anchor"] check had never
+ before run [Temporal_of.anchors] against [Temporal_of.temporal] for
+ real. Normae n. 35(a)'s own text is "Dominica infra octavam Nativitatis,
+ VEL, EA DEFICIENTE, die 30 decembris" -- the Holy Family fallback is a
+ FIXED-DATE fallback (30 December, whatever weekday it falls on that
+ year), confirmed by {!Temporal_of.holy_family}'s own [None -> mk y 12 30]
+ branch and its own .mli citation ("this 6-day window CAN be [empty of a
+ Sunday] -- confirmed by the fallback clause's own existence"). But
+ {!Temporal_of.temporal} used to only ever TEST [same d (holy_family y)]
+ inside its [sunday_slug d] dispatch arm -- i.e. only when [d] genuinely
+ WAS a Sunday -- so in a year whose 26-31 December window had NO Sunday
+ (equivalently: 25 December, Christmas Day, is itself a Sunday), the
+ fallback date was computed correctly by [holy_family]/[anchors] but
+ [temporal] itself silently fell through to an ordinary ferial slug
+ instead (["of-christmas-0-friday"] et al.) -- exactly the "generic day
+ slug masking a real named feast" shape CLAUDE.md already records EF's
+ own Holy Family/Holy Name gaps as, before they were fixed there. Not
+ rare: this fired whenever Christmas Day is a Sunday, roughly one year in
+ seven. [Temporal_of.temporal] now consults [Temporal_of.holy_family]
+ directly in that dispatch arm, independent of weekday, carrying the
+ identical identity (subject Lord, [holy_family_names], rank Festum) the
+ Sunday case already builds -- see temporal_of.ml's own citation on that
+ branch. [is_known_holy_family_fallback_gap] is kept, not deleted, but is
+ no longer in [is_known]'s own filter below -- the same discipline
+ [is_known_nativity_gap] above already established once ITS defect
+ closed: it exists ONLY as an explicit, named "this must never fire
+ again" check ({!check_year_allowing_known_gaps}'s own dedicated
+ assertion), not silently absorbed. *)
let is_known_holy_family_fallback_gap (f : Val.failure) =
f.Val.check = "anchor" && contains ~substring:"of-holy-family" f.Val.detail
let check_year_allowing_known_gaps year =
let fs = run year in
(* Fix wave I8: [is_known_nativity_gap] is deliberately NOT part of
- [is_known] any more -- see that predicate's own header. Only the
- Holy Family fallback gap is still filtered out here. *)
- let is_known f = is_known_holy_family_fallback_gap f in
+ [is_known] any more -- see that predicate's own header. W2 fix: neither
+ is [is_known_holy_family_fallback_gap] now -- see ITS own header. No
+ known gaps remain filtered here (landmark years validate cleanly, full
+ stop); [is_known] is kept as a named hook rather than inlined to
+ [false] so a future gap has an obvious place to land. *)
+ let is_known (_ : Val.failure) = false in
let unexpected = List.filter (fun f -> not (is_known f)) fs in
(match unexpected with
| [] -> ()
@@ -157,7 +160,10 @@ let check_year_allowing_known_gaps year =
(String.concat "; " (List.map Val.failure_to_string (List.filteri (fun i _ -> i < 5) fs))));
Alcotest.(check int)
(Printf.sprintf "%d: no of-nativity citations-unresolved/formulary gap (fix wave I8 -- was 2)" year)
- 0 (List.length (List.filter is_known_nativity_gap fs))
+ 0 (List.length (List.filter is_known_nativity_gap fs));
+ Alcotest.(check int)
+ (Printf.sprintf "%d: no Holy Family anchor gap (W2 fix -- was 1)" year)
+ 0 (List.length (List.filter is_known_holy_family_fallback_gap fs))
(* Landmark years, the same choice test_validate.ml's own
[test_landmark_years] makes for EF: both domain edges plus two ordinary
@@ -220,8 +226,15 @@ let test_year_9999_does_not_raise () =
also the ONLY unexplained [anchors]/[temporal] drift anywhere in the
domain -- the other two items in this paragraph (the lectionary
weekday-cycle-letter asymmetry, and the Holy Family 30-December
- fallback {!is_known_holy_family_fallback_gap} below already pins) are
- unrelated and remain open, unchanged by this fix. *)
+ fallback {!is_known_holy_family_fallback_gap} below already pins) were
+ unrelated and remained open, unchanged by this fix.
+
+ CORRECTED AGAIN (W2, CLAUDE.md, same day): the Holy Family 30-December
+ fallback named just above is ALSO now fixed -- {!Temporal_of.temporal}
+ consults {!Temporal_of.holy_family} directly, independent of weekday.
+ Only the lectionary weekday-cycle-letter asymmetry remains open; it is
+ untouched by this fix (lectionary_of.*/data/of/lectionary.sexp are out
+ of scope here, per the original paragraph's own citation). *)
let sample_years =
let rec range a b = if a > b then [] else a :: range (a + 1) b in
range 2005 2050
@@ -320,28 +333,35 @@ let test_joseph_palm_sunday_2062_anticipated_backward () =
transfer placement anywhere in it)" false
(List.exists (fun f -> f.Val.check = "unconverged") failures)
-(* Second NEWLY-FOUND defect, pinned the same way (see
- [is_known_holy_family_fallback_gap]'s own citation just above for the
- full argument): 1583 is the domain floor AND a year Christmas Day falls
- on a Sunday, so 26-31 December has no Sunday of its own and
- [Temporal_of.holy_family] falls back to its own fixed 30 December --
- correctly, per [Temporal_of.anchors] -- but [Temporal_of.temporal]
- itself never reaches that fallback (its Holy-Family test lives inside
- the Sunday-only dispatch arm), so 30 December 1583 is observed as an
- ordinary Friday-of-Christmastide ferial office instead of the Feast of
- the Holy Family. *)
-let test_holy_family_fallback_1583_known_wrong_ferial () =
+(* CLOSED, W2 fix (CLAUDE.md). This test used to pin a defect the same way
+ [is_known_holy_family_fallback_gap]'s own citation just above describes:
+ 1583 is the domain floor AND a year Christmas Day falls on a Sunday, so
+ 26-31 December has no Sunday of its own and [Temporal_of.holy_family]
+ falls back to its own fixed 30 December -- correctly, per
+ [Temporal_of.anchors] -- but [Temporal_of.temporal] used to never reach
+ that fallback (its Holy-Family test lived inside the Sunday-only dispatch
+ arm), so 30 December 1583 was observed as an ordinary
+ Friday-of-Christmastide ferial office instead of the Feast of the Holy
+ Family. Now that {!Temporal_of.temporal} consults {!Temporal_of
+ .holy_family} directly, this test asserts the FIXED, correct behaviour
+ instead -- through the full real-data {!Colitur_kernel.Calendar}/
+ {!Colitur_kernel.Precedence} pipeline, not merely {!Temporal_of.temporal}
+ in isolation (test_temporal_of.ml's own
+ [test_holy_family_fallback_temporal] already covers that layer) --
+ checking identity (subject, rank), not only the slug, so a fix that
+ landed the right slug on the wrong grade would still be caught. *)
+let test_holy_family_fallback_1583_now_correct () =
let christmas_1583 = Date.of_iso8601 "1583-12-25" |> Result.get_ok in
Alcotest.(check bool) "1583 Christmas Day really is a Sunday (the Normae n.35(a) trigger)" true
(Date.weekday christmas_1583 = Date.Sun);
let days = Cal.year real_of_rite real_of_layer 1583 in
let dec30 = Array.to_list days |> List.find (fun d -> Date.compare d.LD.date (Date.add_days christmas_1583 5) = 0) in
- Alcotest.(check string)
- "KNOWN WRONG (Normae n.35(a) fallback unreached, see [is_known_holy_family_fallback_gap]'s own \
- citation): 30 December 1583 is an ordinary ferial slug, not of-holy-family"
- "of-christmas-0-friday" (slug_of dec30.LD.observed);
- Alcotest.(check bool) "and that really is NOT the Holy Family (confirming this really is the defect)" false
- (slug_of dec30.LD.observed = "of-holy-family")
+ Alcotest.(check string) "FIXED (W2): 30 December 1583 is observed as of-holy-family, not an ordinary ferial"
+ "of-holy-family" (slug_of dec30.LD.observed);
+ Alcotest.(check string) "subject is Lord (same identity the Sunday case carries)" "lord"
+ (Colitur_kernel.Subject.to_string dec30.LD.observed.Cel.subject);
+ Alcotest.(check string) "rank is Festum, not a lesser grade" "festum"
+ (V.rank_to_string dec30.LD.observed.Cel.rank)
(* Fix wave I6 (final-review.md, 2026-08-25-colitur-of-phases-3-5): the
obligatory-memorial tie data/of/amendments/006-mary-mother-of-the-church
@@ -399,7 +419,7 @@ let test_mater_ecclesiae_anthony_tie_2011_known_arbitrary () =
let suite =
( "Rite_of (real data: assembled Rite.t end-to-end via Calendar/Validate)",
- [ Alcotest.test_case "landmark years validate cleanly (modulo two documented gaps)" `Quick
+ [ Alcotest.test_case "landmark years validate cleanly (W2 and the nativity gap both closed)" `Quick
test_landmark_years;
Alcotest.test_case "year 9999 does not raise; seasons flags the clamp, coverage stays clean" `Quick
test_year_9999_does_not_raise;
@@ -410,9 +430,9 @@ let suite =
n.56(f), converges, and is recorded as an arrival" `Quick
test_joseph_palm_sunday_2062_anticipated_backward;
Alcotest.test_case
- "NEWLY-FOUND DEFECT pinned, not fixed: Holy Family's Normae n.35(a) 30-December fallback is \
- unreached when Christmas Day is a Sunday (1583)" `Quick
- test_holy_family_fallback_1583_known_wrong_ferial;
+ "FIXED (W2): Holy Family's Normae n.35(a) 30-December fallback is now reached when Christmas \
+ Day is a Sunday (1583)" `Quick
+ test_holy_family_fallback_1583_now_correct;
Alcotest.test_case
"KNOWN ARBITRARY pinned: Mary Mother of the Church vs Anthony of Padua tie, 2011-06-13 \
(Easter+50)" `Quick