diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-26 23:45:16 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-26 23:45:16 +0200 |
| commit | 9ebb06983b7a26db5564302253f2551dfbcf834e (patch) | |
| tree | f73de5c193a13239258d062ca5f4caf64ba64dbe /test/test_rite_of.ml | |
| parent | 2f6d25aff88b4c76c61e36889f1c017b3cc8faee (diff) | |
| download | colitur-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.ml | 136 |
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 |
