(* Table-driven, one Alcotest case per Tabula entry, so a transcription error names the entry it broke. Mirrors test/test_precedence_ef.ml. *) open Colitur_kernel module Vocab_of = Rite_of.Vocab_of let mk_cel ?(layer = Rite_of.Precedence_of.universal_layer) ?(status = Celebration.Feast) ?(colour = Colour.White) ?(subject = Subject.Saint) ~slug ~rank () = { Celebration.slug = Slug.of_string_exn slug; names = Names.empty; rank; status; colour; subject; citations = []; layer } let mk ?layer ?status ?colour ?subject ~slug ~rank ~origin () = { Precedence.cel = mk_cel ?layer ?status ?colour ?subject ~slug ~rank (); origin } let ctx ~iso ~season = let date = Date.of_iso8601 iso |> Result.get_ok in { Precedence.date; season; weekday = Date.weekday date } (* Each row: label, context, candidate, expected band value. *) let part1_cases = [ ( "entry 1: Good Friday", ctx ~iso:"2026-04-03" ~season:Vocab_of.Lent, mk ~slug:"of-lent-6-friday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 10 ); ( "entry 1: Holy Saturday", ctx ~iso:"2026-04-04" ~season:Vocab_of.Lent, mk ~slug:"of-lent-6-saturday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 10 ); ( "entry 1: Easter Sunday", ctx ~iso:"2026-04-05" ~season:Vocab_of.Easter, mk ~slug:"of-easter-sunday" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), 10 ); ( "entry 2: Holy Thursday is a Holy Week feria, not the Triduum", ctx ~iso:"2026-04-02" ~season:Vocab_of.Lent, mk ~slug:"of-lent-6-thursday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 20 ); ( "entry 2: the Nativity", ctx ~iso:"2026-12-25" ~season:Vocab_of.Christmas, mk ~slug:"of-nativity" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), 20 ); ( "entry 2: a Sunday of Advent", ctx ~iso:"2026-11-29" ~season:Vocab_of.Advent, mk ~slug:"of-advent-sunday-1" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), 20 ); ( "entry 2: Ash Wednesday", ctx ~iso:"2026-02-18" ~season:Vocab_of.Lent, mk ~slug:"of-ash-wednesday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 20 ); ( "entry 2: a day within the Octave of Easter", ctx ~iso:"2026-04-07" ~season:Vocab_of.Easter, mk ~slug:"of-easter-octave-day-3" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), 20 ); ( "entry 3: a universal solemnity of a saint", ctx ~iso:"2026-06-29" ~season:Vocab_of.Ordinary_time, mk ~slug:"of-peter-and-paul" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Sanctoral (), 30 ); ( "entry 4: a proper solemnity", ctx ~iso:"2026-06-29" ~season:Vocab_of.Ordinary_time, mk ~layer:"proper:diocese-of-poznan" ~slug:"of-local-patron" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Sanctoral (), 40 ) ] let test_part1 () = List.iter (fun (label, c, cand, expected) -> Alcotest.(check int) label expected (Rite_of.Precedence_of.band c cand)) part1_cases let part2_cases = [ ( "entry 5: a universal feast of the Lord", ctx ~iso:"2026-08-06" ~season:Vocab_of.Ordinary_time, mk ~subject:Subject.Lord ~slug:"of-transfiguration" ~rank:Vocab_of.Festum ~origin:Precedence.Sanctoral (), 50 ); ( "entry 6: a Sunday per annum", ctx ~iso:"2026-07-12" ~season:Vocab_of.Ordinary_time, (* rank is Festum, not the brief's original Sollemnitas: a real Sunday per annum is never Sollemnitas (temporal_of.ml only grades Advent, Lent and Easter Sundays that way, and those are entry 2, tested before this one), and a Sollemnitas candidate here would hit entry 3 first regardless of layer -- the brief's own adjacent "Sunday of Christmas time" row already uses Festum for the identical reason. *) mk ~slug:"of-ordinary-time-sunday-15" ~rank:Vocab_of.Festum ~origin:Precedence.Temporal (), 60 ); ( "entry 6: a Sunday of Christmas time", ctx ~iso:"2027-01-03" ~season:Vocab_of.Christmas, mk ~slug:"of-christmas-sunday-2" ~rank:Vocab_of.Festum ~origin:Precedence.Temporal (), 60 ); ( "entry 7: a universal feast of a saint", ctx ~iso:"2026-04-25" ~season:Vocab_of.Easter, mk ~subject:Subject.Saint ~slug:"of-mark" ~rank:Vocab_of.Festum ~origin:Precedence.Sanctoral (), 70 ); ( "entry 7: a universal feast of the BVM", ctx ~iso:"2026-05-31" ~season:Vocab_of.Ordinary_time, mk ~subject:Subject.Bvm ~slug:"of-visitation" ~rank:Vocab_of.Festum ~origin:Precedence.Sanctoral (), 70 ); ( "entry 8: a proper feast", ctx ~iso:"2026-04-25" ~season:Vocab_of.Easter, mk ~layer:"proper:diocese-of-poznan" ~slug:"of-cathedral-dedication" ~rank:Vocab_of.Festum ~origin:Precedence.Sanctoral (), 80 ); ( "entry 9: an Advent feria on 17 December", ctx ~iso:"2026-12-17" ~season:Vocab_of.Advent, mk ~slug:"of-advent-3-thursday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 90 ); ( "entry 9: a day within the Octave of the Nativity", ctx ~iso:"2026-12-29" ~season:Vocab_of.Christmas, mk ~slug:"of-christmas-0-tuesday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 90 ); ( "entry 9: a Lenten feria", ctx ~iso:"2026-03-03" ~season:Vocab_of.Lent, mk ~slug:"of-lent-2-tuesday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), 90 ); (* MY RULING (2026-08-25, task-2-brief correction): every temporal-origin celebration Temporal_of.temporal constructs carries [layer = "temporal"], never [Precedence_of.universal_layer] -- so entries 3, 5 and 7 must test [not (is_proper layer)], not [is_universal layer]. These four rows pin exactly what that correction fixes: without it, Corpus Christi comes out unclassified (a hole) and Trinity/Christ the King land at entry 6 instead of entry 3. *) ( "entry 3: Trinity Sunday is a solemnity of the general calendar", ctx ~iso:"2026-05-31" ~season:Vocab_of.Ordinary_time, mk ~slug:"of-trinity" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), 30 ); ( "entry 3: Corpus Christi, a Thursday, is not unclassified", ctx ~iso:"2026-06-04" ~season:Vocab_of.Ordinary_time, mk ~slug:"of-corpus-christi" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), 30 ); ( "entry 5: the Baptism of the Lord is a feast OF THE LORD", ctx ~iso:"2026-01-11" ~season:Vocab_of.Christmas, mk ~subject:Subject.Lord ~slug:"of-baptism-of-the-lord" ~rank:Vocab_of.Festum ~origin:Precedence.Temporal (), 50 ); ( "entry 6, not 5: an ordinary Christmas Sunday has no Lord subject", ctx ~iso:"2027-01-03" ~season:Vocab_of.Christmas, mk ~subject:Subject.Temporal ~slug:"of-christmas-sunday-2" ~rank:Vocab_of.Festum ~origin:Precedence.Temporal (), 60 ) ] let test_part2 () = List.iter (fun (label, c, cand, expected) -> Alcotest.(check int) label expected (Rite_of.Precedence_of.band c cand)) part2_cases let suite = ( "precedence-of", [ Alcotest.test_case "Tabula part I (entries 1-4)" `Quick test_part1; Alcotest.test_case "Tabula part II (entries 5-9)" `Quick test_part2 ] )