diff options
| -rw-r--r-- | lib/rites/rite_of/precedence_of.ml | 41 | ||||
| -rw-r--r-- | test/test_precedence_of.ml | 71 |
2 files changed, 97 insertions, 15 deletions
diff --git a/lib/rites/rite_of/precedence_of.ml b/lib/rites/rite_of/precedence_of.ml index 0e2c246..30fe48e 100644 --- a/lib/rites/rite_of/precedence_of.ml +++ b/lib/rites/rite_of/precedence_of.ml @@ -465,20 +465,33 @@ let max_search_days = 400 let domain_max_date = match Date.make ~year:9999 ~month:12 ~day:31 with Ok d -> d | Error e -> failwith e -(* NOTE, found while adding [st_joseph_slug] below, NOT fixed here -- - out of scope for the W1 task this touches: [annunciation_slug] does not - match the real shipped entry's own slug (data/of/calendar-2002.sexp has - "annunciation-of-the-lord", not "of-annunciation"), so Rule 1 below - never actually fires against real sanctoral data -- only against the - synthetic candidate test_precedence_of.ml's own [annunciation] builds - with the same placeholder slug. Whether this is output-visible on real - data was not established either way here; Rule 3's general forward - search is a plausible fallback that could reach the identical Easter+8 - target by coincidence in the one case tested - ([test_annunciation_in_easter_octave]'s own comment says as much for a - collision NOT in Holy Week), but that is not the same claim as "the two - rules always agree", and this was not checked for Holy Week itself. *) -let annunciation_slug = "of-annunciation" +(* W6 (of-known-wrongs, 2026-08-26; found by W1, fixed here). This used to + read "of-annunciation", a placeholder that never matched the real + shipped entry's own slug (data/of/calendar-2002.sexp has + "annunciation-of-the-lord") -- so Rule 1 below was DEAD CODE: it could + only ever fire against test_precedence_of.ml's own synthetic candidate, + which happened to carry the identical placeholder, never against real + sanctoral data. + + LATENT, NOT LIVE, on shipped data: Rule 3's general forward search + structurally converges on the identical Easter+8 target whenever the + Annunciation falls in Holy Week, because the Easter Octave occupies + exactly Easter+1..+7 at band 20 and 3-9 April (where Easter+8 lands) + carries only memorials on the shipped universal calendar -- confirmed, + not merely argued, by test_precedence_of.ml's own + [test_annunciation_rule1_actually_fires], which rigs a synthetic + Tabula-entry-3 occupant AT Easter+8 and shows Rule 3 alone would have + had to step past it to Easter+9, while the REAL slug (fixed here) makes + Rule 1 land on Easter+8 regardless -- the one test in this file that + tells "Rule 1 fired" apart from "Rule 3 happened to agree", which no + test here did before it. + + LIVE the moment an overlay places a proper solemnity (band 40) or + proper feast (band 80) anywhere in 3-9 April: Rule 3 would then diverge + from n. 60's own fixed Easter+8 destination, and with the placeholder + slug Rule 1 would silently fail to override it. Fixed at the source + instead of documented around. *) +let annunciation_slug = "annunciation-of-the-lord" (* The real shipped slug (data/of/calendar-2002.sexp) -- St Joseph's own Rule 0 below is matched against the actual sanctoral entry, not a diff --git a/test/test_precedence_of.ml b/test/test_precedence_of.ml index e2e8540..01ba92c 100644 --- a/test/test_precedence_of.ml +++ b/test/test_precedence_of.ml @@ -375,8 +375,18 @@ let test_vigil_feast_is_always_none () = rather than a hand-made fiction. *) let occupant d = (Rite_of.Temporal_of.temporal d).Temporal.office +(* W6 (of-known-wrongs, 2026-08-26): this used to carry the placeholder slug + "of-annunciation" -- the very bug precedence_of.ml's own [annunciation_ + slug] carried, so this synthetic candidate coincidentally matched the + bug rather than testing against it. Now the REAL shipped slug + (data/of/calendar-2002.sexp: "annunciation-of-the-lord"), so the tests + below that use it (Rule 1/n. 60) actually exercise Rule 1 against the + slug production code now checks -- see + [test_annunciation_rule1_actually_fires] below for the test that tells + "Rule 1 fired" apart from "Rule 3 happened to agree", which none of + these did before it. *) let annunciation = - mk ~subject:Subject.Lord ~slug:"of-annunciation" ~rank:Vocab_of.Sollemnitas + mk ~subject:Subject.Lord ~slug:"annunciation-of-the-lord" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Sanctoral () let iso s = Date.of_iso8601 s |> Result.get_ok @@ -524,6 +534,62 @@ let test_all_souls_beats_an_ordinary_sunday () = Alcotest.(check bool) "All Souls, not the Sunday, is observed" true (resolution.Precedence.observed = all_souls_candidate) +(* W6 (of-known-wrongs, 2026-08-26). [annunciation_slug] used to read + "of-annunciation", a placeholder that never matched the real shipped + entry -- Rule 1 (Normae n. 60's fixed Easter+8 destination) was DEAD + CODE, only ever exercised by this file's own synthetic candidate, which + happened to carry the identical placeholder. Every test above this one + proves nothing about whether Rule 1 fires against real data: they all + land on Easter+8, but Rule 3's general forward search converges on the + IDENTICAL date whenever the 3-9 April window is empty of anything at + Tabula entries 1-8 (true on the shipped universal calendar), so the + output is the same whichever rule actually answers. + + This test tells the two apart. It loads the REAL shipped + "annunciation-of-the-lord" entry (not a synthetic reconstruction, the + same discipline [test_all_souls_beats_an_ordinary_sunday] above uses) + and RIGS the [occupant] callback to occupy Easter+8 itself with a + synthetic Tabula-entry-3 candidate (band 30, well inside entries 1-8). + Rule 3's search, if it were what answered, would have to step past that + occupied day onto Easter+9 -- confirmed by a CONTROL case, a different + solemnity on the same origin and the same rig, which can only reach + Rule 3 (it is neither the Annunciation nor St Joseph on Palm Sunday) and + does indeed land on Easter+9. Rule 1's own fixed computation never + consults [occupant] at all, so the rig has no effect on it: the real + Annunciation still landing on Easter+8 DESPITE the block is something + only Rule 1 firing can explain. *) +let test_annunciation_rule1_actually_fires () = + let path = "../data/of/calendar-2002.sexp" in + let l = + match Colitur_kernel.Layer.load Vocab_of.rank_of_sexp path with + | Ok l -> l + | Error e -> Alcotest.failf "%s: failed to load: %s" path e + in + let annunciation_real = + match Colitur_kernel.Layer.find l (Slug.of_string_exn "annunciation-of-the-lord") with + | Some e -> { Precedence.cel = e.Colitur_kernel.Layer.cel; origin = Precedence.Sanctoral } + | None -> Alcotest.fail "\"annunciation-of-the-lord\" not found in the shipped calendar" + in + (* 2027: Easter 28 March, so 25 March is Holy Thursday -- inside Holy + Week -- and Easter+8 is 5 April, the date this rig occupies. *) + let origin = iso "2027-03-25" in + let blocked = iso "2027-04-05" in + let rigged d = + if Date.compare d blocked = 0 then + mk_cel ~slug:"of-w6-synthetic-blocker" ~rank:Vocab_of.Sollemnitas () + else occupant d + in + let control = + mk ~slug:"of-w6-control" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Sanctoral () in + let control_target = Rite_of.Precedence_of.transfer_target control origin rigged in + Alcotest.(check string) + "control (not the Annunciation, not St Joseph): the rig really blocks -- pushed past 5 April to 6 April" + "2027-04-06" (Date.to_iso8601 control_target); + let target = Rite_of.Precedence_of.transfer_target annunciation_real origin rigged in + Alcotest.(check string) + "the REAL shipped Annunciation still lands on Easter+8 despite the block -- Rule 1, not Rule 3, fired" + "2027-04-05" (Date.to_iso8601 target) + (* W3 (of-known-wrongs, 2026-08-26). Mary, Mother of the Church (Easter+50) and a fixed obligatory memorial (e.g. Anthony of Padua, 13 June) both used to band at Tabula III.10 (100) whenever they coincide -- a tie @@ -605,6 +671,9 @@ let suite = "fix round 2: shipped All Souls beats an ordinary per-annum Sunday (2025-11-02)" `Quick test_all_souls_beats_an_ordinary_sunday; Alcotest.test_case + "W6: the REAL shipped Annunciation slug makes Rule 1 fire (not merely agree with Rule 3)" `Quick + test_annunciation_rule1_actually_fires; + Alcotest.test_case "W3: a movable BVM obligatory memorial beats a fixed one, per the CDWDS's 24 March 2018 \ Notification" `Quick test_movable_bvm_memorial_beats_a_fixed_one ] |
