From 21dab521d6bfe8e4e7d04f761c11754059339ba2 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Tue, 11 Aug 2026 23:46:51 +0200 Subject: test(ef): prove the II-class-Sunday privilege override end-to-end Adds test_ii_class_sunday_privileged_witness_admitted_end_to_end, proving RG 111's "II-class Sundays: one, dropped if a privileged one is due" clause through the real pipeline (band, disposition, privilege_of, admit together), not only at the isolated admit level. RG 109(b) is the one privileged category that is sanctoral and rank-based rather than temporal-origin: a Commemoration_only, Class1 sanctoral candidate (the same shape disposition_cases already uses as (b)'s witness) is held out of the band contest entirely by Precedence.resolve, so it always loses regardless of what wins the day. Paired with an ordinary sanctoral saint, both losing to an ordinary Class2 Sunday, gives observed_is_sunday = true with one privileged and one ordinary loser due at once, with no new fixture. Documents, and mutation-confirms, what this fixture does and does not prove: RG 109(b)'s only reachable witness is Class1 (the highest dignity), so the privileged loser here is unavoidably also the higher-dignity one, and the admission outcome alone cannot distinguish "privilege overrides dignity" from "dignity alone picked the same winner" -- that distinction remains admit_cases's job. What this test does prove, and what a category-(b) regression in privilege_of breaks, is the privilege tag itself surviving the real pipeline end-to-end. --- test/test_precedence_ef.ml | 68 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml index 09c41fd..a95b321 100644 --- a/test/test_precedence_ef.ml +++ b/test/test_precedence_ef.ml @@ -676,6 +676,69 @@ let test_privileged_lent_feria_admitted_end_to_end () = resolution.P.commemorations); Alcotest.(check int) "nothing omitted" 0 (List.length resolution.P.omitted) +(* Fix round 1 (post-Task-9 review): the II-class-Sunday override (RG 111 + "one, dropped if a privileged one is due") reached through the REAL + pipeline, with both a privileged AND an ordinary commemoration due on the + same day -- previously only proven at the isolated [admit] level + ([admit_cases]'s hand-tagged rows above). RG 109(a)-(f)'s five reachable + categories are all properties of a TEMPORAL-origin office, and only one + temporal candidate exists per date, so a privileged AND an ordinary + commemoration cannot both be due from the temporal side alone -- but + category (b) is the exception: it is sanctoral and rank-based (a + [Commemoration_only] entry carrying [Class1], the exact shape + [disposition_cases]'s own (b) witness row uses), and a [Commemoration_only] + entry is held out of the band contest entirely ({!Precedence.resolve}), + so it is a loser regardless of what [observed] turns out to be. Paired + with an ordinary sanctoral saint, both lose to an ordinary Class2 Sunday, + giving [observed_is_sunday = true] with one [Privileged] and one + [Ordinary] loser due at once -- no synthetic fixture needed. + + NOTE on what this test does and does not prove: the only reachable + witness for RG 109(b) is [Class1] (the highest dignity), and any + sanctoral loser that could ALSO beat this same Sunday by pure dignity + would win the day outright instead of losing to it (any [Feast]-status + [Class1] sanctoral candidate bands at entry 11-13, ahead of an ordinary + Sunday's entry 15) -- so within this specific pipeline shape the + privileged loser is unavoidably also the higher-dignity one, and this + test cannot by itself distinguish "privilege overrides dignity" from + "dignity alone happened to pick the same winner". That distinction is + what [admit_cases]'s hand-tagged rows above prove (a LOWER-dignity + privileged candidate still beats a HIGHER-dignity ordinary one on a + II-class Sunday, the opposite of "other II class"'s own row). This test's + job is narrower and complementary: proving the real pipeline + ([PE.band], [PE.disposition], [PE.privilege_of] via [disposition], + [PE.admit] together) actually reaches and exercises the override branch + end-to-end, not merely in isolation. *) +let test_ii_class_sunday_privileged_witness_admitted_end_to_end () = + let date = mk 2026 7 5 (* an ordinary Time-after-Pentecost Sunday. *) in + let day_ctx = ctx date in + let sunday = of_temporal date in + let privileged_witness = + cand ~origin:P.Sanctoral ~status:Cel.Commemoration_only ~layer:PE.universal_layer + "ef-commemoration-only-b-witness" + (* Class1 by [cand]'s own default -- RG 109(b). *) + in + let ordinary_saint = cand ~origin:P.Sanctoral ~rank:V.Class2 ~layer:PE.universal_layer "ef-some-saint" in + let resolution = + P.resolve real_rules day_ctx ~temporal:sunday ~sanctoral:[ privileged_witness; ordinary_saint ] + in + (* Checked against [sunday]'s own slug, not a hand-typed/guessed literal + (its exact week number is not worth independently re-deriving here): + this asserts identity with the real [Temporal_ef.temporal] candidate, + proving the SUNDAY -- not either sanctoral loser -- is what wins the + day, which the privilege assertions below presuppose. *) + Alcotest.(check string) "the Sunday wins the day, not either sanctoral loser" + (S.to_string sunday.P.cel.Cel.slug) (S.to_string resolution.P.observed.P.cel.Cel.slug); + Alcotest.(check (list (pair string string))) + "only the privileged (Commemoration_only, Class1) witness is admitted" + [ ("ef-commemoration-only-b-witness", "Privileged") ] + (List.map + (fun (c, p) -> (S.to_string c.P.cel.Cel.slug, match p with P.Privileged -> "Privileged" | P.Ordinary -> "Ordinary")) + resolution.P.commemorations); + Alcotest.(check (list (pair string string))) "the ordinary saint is dropped into omitted, not vanished" + [ ("ef-some-saint", "omitted: admission limit reached") ] + (List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted) + (* Completes Task 7's carried fix (register line 334): on a real Sunday landing on 2 November, All Souls does not merely lose (that was Task 7's [band] fix, proved by [test_all_souls_yields_to_sunday] above) -- it must @@ -753,4 +816,7 @@ let suite = Alcotest.test_case "II-class Sunday: second loser dropped into omitted" `Quick test_ii_class_sunday_drops_second_loser_into_omitted; Alcotest.test_case "RG109(e) Lent feria privileged end-to-end" `Quick - test_privileged_lent_feria_admitted_end_to_end ] ) + test_privileged_lent_feria_admitted_end_to_end; + Alcotest.test_case + "II-class Sunday override: RG109(b) witness admitted over an ordinary saint, end-to-end" + `Quick test_ii_class_sunday_privileged_witness_admitted_end_to_end ] ) -- cgit v1.3