From d2bfeb3c9b5cff163ed9cd9e86eb0e1849117f67 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 13 Aug 2026 13:12:01 +0200 Subject: temporal(ef): the Sacred Triduum's own Latin identity, RG 91 entry 2 Holy Thursday, Good Friday and Holy Saturday resolved to the generic Passiontide ferial slugs with no distinct identity of their own -- rank and colour were already correct (RG 91 entry 2; Holy Thursday's white per RG 128(b)/RG 122), only Celebration.names/subject were missing. Keeps the slug (RG 91 entry 2 is identified structurally, off rank and Easter offset, by Precedence_ef.band -- never off the slug -- so renaming it would touch precedence for no reason and break the lectio differential's own slug mapping for these three lectionary keys, the same reasoning already given for Holy Family/Holy Name). Carries the identity in Celebration.names instead, the same treatment those two established: Latin, not English, to avoid reading the oracle this axis is compared against. Names sourced from both photographic scans, word for word, corroborated by the electronic transcription's own table-of-contents-style listing at the identical three headings (three-way agreement, nothing to adjudicate): "Feria V in Cena Domini" (Holy Thursday), "Feria VI in Passione et Morte Domini" (Good Friday -- not the transcription's own informal "Feria VI Parasceve" used in passing elsewhere), "Sabbato Sancto" (Holy Saturday). Also tags subject = Lord, going further than Holy Family/Holy Name strictly required (they needed it only because band's entry 14 reads subject to outrank a colliding fixed feast; entry 2 here needs no such thing). Safe: disposition's RG 112(a) branch only fires when both sides of an occurrence are tagged Lord, and no Lord-subject sanctoral entry has a fixed civil date inside Holy Week's own movable range; any Class1 sanctoral entry landing there (e.g. a transferred Annunciation) reaches disposition's earlier, subject-blind Transfer branch first regardless. Verified against the full 1583-9999 domain: zero observed/commemorations/transferred_* difference traceable to the tag. test_golden.ml's describe gains a name_la field alongside subject, for the same reason subject was added: a names-only change is otherwise invisible to every pin whose rank/colour/slug are already correct (this task's own catalogued vacuity flavour #1). Six existing pins move from subject=temporal to subject=lord (the three Easter-extreme Holy Saturday pins, 2016's Good Friday, and the 2026 Holy Thursday/Good Friday pair); the rest gain name_la=- by construction (no other temporal-cycle candidate carries a name yet). Mutation-tested: reverting temporal_ef.ml alone (keeping the tests) reddens the new Rite_ef unit test plus five golden pins across two independent layers. --- test/test_golden.ml | 124 ++++++++++++++++++++++++++--------------------- test/test_temporal_ef.ml | 81 +++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 55 deletions(-) (limited to 'test') diff --git a/test/test_golden.ml b/test/test_golden.ml index 0f90ee7..68478ec 100644 --- a/test/test_golden.ml +++ b/test/test_golden.ml @@ -94,6 +94,8 @@ let slug_s (c : V.rank Cel.t) = Slug.to_string c.Cel.slug let rank_s (c : V.rank Cel.t) = V.rank_to_string c.Cel.rank let colour_s (c : V.rank Cel.t) = Colour.to_string c.Cel.colour let subject_s (c : V.rank Cel.t) = Colitur_kernel.Subject.to_string c.Cel.subject +let la = Colitur_kernel.Lang.of_string_exn "la" +let name_la_s (c : V.rank Cel.t) = match Colitur_kernel.Names.find c.Cel.names la with Some n -> n | None -> "-" let privilege_s = function Prec.Privileged -> "privileged" | Prec.Ordinary -> "ordinary" (* fix round 1 (coordinator finding 4): [subject] added. Two of the three @@ -107,7 +109,19 @@ let privilege_s = function Prec.Privileged -> "privileged" | Prec.Ordinary -> "o The five fields {!Colitur_kernel.Liturgical_day.t} promises are never silently lost, folded into one comparable line -- see the file header for - why one string, not five checks. *) + why one string, not five checks. + + ef-triduum-litanies task (Gap 1), same lesson applied pre-emptively rather + than caught after the fact: [name_la] added for the SAME reason [subject] + was -- a names-only change (the Sacred Triduum's own Latin identity, RG 91 + entry 2) would otherwise be invisible to every pin whose rank/colour/slug + are already correct (this project's own catalogued vacuity flavour #1, + "an assertion already true before the code under test ran" -- this task's + own hazard, stated in its brief). Read off [Cel.names]'s own Latin entry + (the same field/language {!Cel.of_list}'s callers in temporal_ef.ml use + for Holy Family/Holy Name/the Triduum -- no temporal-cycle candidate + currently carries any OTHER language), "-" for none, matching [week]'s + own None-as-"-" convention immediately above. *) let describe (day : (V.season, V.rank) LD.t) = let t = day.LD.temporal in let week = match t.Temporal.week with Some n -> string_of_int n | None -> "-" in @@ -120,12 +134,12 @@ let describe (day : (V.season, V.rank) LD.t) = List.map (fun (c, d) -> Printf.sprintf "%s->%s" (slug_s c) (Date.to_iso8601 d)) day.LD.transferred_out |> List.sort compare |> String.concat "," in - Printf.sprintf "%s %s season=%s week=%s slug=%s rank=%s colour=%s subject=%s comms=[%s] in=%s out=[%s]" + Printf.sprintf "%s %s season=%s week=%s slug=%s rank=%s colour=%s subject=%s name_la=%s comms=[%s] in=%s out=[%s]" (Date.to_iso8601 day.LD.date) (Date.weekday_to_string t.Temporal.weekday) (V.season_to_string t.Temporal.season) week (slug_s day.LD.observed) (rank_s day.LD.observed) (colour_s day.LD.observed) - (subject_s day.LD.observed) comms tin tout + (subject_s day.LD.observed) (name_la_s day.LD.observed) comms tin tout let check ~msg y m d expected = Alcotest.(check string) msg expected (describe (fetch y m d)) @@ -150,11 +164,11 @@ let omitted_has (day : (V.season, V.rank) LD.t) slug = place, not merely that 22 March is white. *) let test_easter_extreme_1598 () = check ~msg:"1598-03-21 Holy Saturday: still Passiontide, violet (RG 128)" 1598 3 21 - "1598-03-21 saturday season=passiontide week=2 slug=ef-passiontide-2-saturday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[]"; + "1598-03-21 saturday season=passiontide week=2 slug=ef-passiontide-2-saturday rank=class-1 colour=violet subject=lord \ + name_la=Sabbato Sancto comms=[] in=- out=[]"; check ~msg:"1598-03-22 earliest possible Easter (Gauss-verified): Paschaltide begins, white, class-1" 1598 3 22 - "1598-03-22 sunday season=paschaltide week=1 slug=ef-easter-sunday rank=class-1 colour=white subject=temporal comms=[] in=- \ + "1598-03-22 sunday season=paschaltide week=1 slug=ef-easter-sunday rank=class-1 colour=white subject=temporal name_la=- comms=[] in=- \ out=[]" (* 1666: latest Gregorian Easter possible, 25 April -- hand-verified via @@ -162,11 +176,11 @@ let test_easter_extreme_1598 () = 25 April). Same citations as 1598 above. *) let test_easter_extreme_1666 () = check ~msg:"1666-04-24 Holy Saturday: still Passiontide, violet (RG 128)" 1666 4 24 - "1666-04-24 saturday season=passiontide week=2 slug=ef-passiontide-2-saturday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[]"; + "1666-04-24 saturday season=passiontide week=2 slug=ef-passiontide-2-saturday rank=class-1 colour=violet subject=lord \ + name_la=Sabbato Sancto comms=[] in=- out=[]"; check ~msg:"1666-04-25 latest possible Easter (Gauss-verified): Paschaltide begins, white, class-1" 1666 4 25 - "1666-04-25 sunday season=paschaltide week=1 slug=ef-easter-sunday rank=class-1 colour=white subject=temporal comms=[] in=- \ + "1666-04-25 sunday season=paschaltide week=1 slug=ef-easter-sunday rank=class-1 colour=white subject=temporal name_la=- comms=[] in=- \ out=[]" (* 2038: the brief's "late modern case" -- Easter also 25 April (Gauss- @@ -191,10 +205,10 @@ let test_easter_extreme_1666 () = though nothing forces that any more). *) let test_easter_extreme_2038_late_modern () = check ~msg:"2038-04-24 Holy Saturday: still Passiontide, violet (RG 128)" 2038 4 24 - "2038-04-24 saturday season=passiontide week=2 slug=ef-passiontide-2-saturday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[]"; + "2038-04-24 saturday season=passiontide week=2 slug=ef-passiontide-2-saturday rank=class-1 colour=violet subject=lord \ + name_la=Sabbato Sancto comms=[] in=- out=[]"; check ~msg:"2038-04-25 late-modern instance of the latest possible Easter (Gauss-verified)" 2038 4 25 - "2038-04-25 sunday season=paschaltide week=1 slug=ef-easter-sunday rank=class-1 colour=white subject=temporal comms=[] in=- \ + "2038-04-25 sunday season=paschaltide week=1 slug=ef-easter-sunday rank=class-1 colour=white subject=temporal name_la=- comms=[] in=- \ out=[]" (* ------------------------------------------------------------------ *) @@ -215,15 +229,15 @@ let test_annunciation_transfer_inside_holy_week_2016 () = actually reaches a live case" for exactly this reason. *) check ~msg:"2016-03-25 Good Friday: Triduum outranks the Annunciation (RG91 entry 2 > 11), no commemoration" 2016 3 25 - "2016-03-25 friday season=passiontide week=2 slug=ef-passiontide-2-friday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[annunciation-of-the-blessed-virgin-mary->2016-04-04]"; + "2016-03-25 friday season=passiontide week=2 slug=ef-passiontide-2-friday rank=class-1 colour=violet subject=lord \ + name_la=Feria VI in Passione et Morte Domini comms=[] in=- out=[annunciation-of-the-blessed-virgin-mary->2016-04-04]"; (* The general RG 96 walk from 26 March would still be inside the Triduum, the Easter octave (all I class, entry 2/10) -- carrying the feast PAST Easter -- so RG 96 Attamen (a)'s condition fires: sedes propria = Monday after Low Sunday = Easter + 8 = 27 Mar + 8 = 4 April. *) check ~msg:"2016-04-04 Easter+8 (Monday after Low Sunday): RG96 Attamen(a) sedes propria fires" 2016 4 4 "2016-04-04 monday season=paschaltide week=2 slug=annunciation-of-the-blessed-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]" + colour=white subject=saint name_la=- comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]" (* ------------------------------------------------------------------ *) (* 2008: the double transfer (register §4, "cases worth adding"). Easter = @@ -239,7 +253,7 @@ let test_annunciation_joseph_double_transfer_2008 () = check ~msg:"2008-03-19 Wednesday of Holy Week outranks Joseph (RG91 entry 7 > 11), no commemoration" 2008 3 19 "2008-03-19 wednesday season=passiontide week=2 slug=ef-passiontide-2-wednesday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[joseph-spouse-of-the-bl-virgin-mary->2008-04-01]"; + name_la=- comms=[] in=- out=[joseph-spouse-of-the-bl-virgin-mary->2008-04-01]"; (* Both Joseph and the Annunciation are band 11 (register: neither is Immaculate Conception/Assumption, band 4; both are ordinary universal I-class feasts). RG 96 Attamen (a) is CONDITIONAL, so it is evaluated @@ -266,7 +280,7 @@ let test_annunciation_joseph_double_transfer_2008 () = check ~msg:"2008-03-31 Easter+8: Annunciation's named sedes propria (RG96 Attamen a) claims the day first" 2008 3 31 "2008-03-31 monday season=paschaltide week=2 slug=annunciation-of-the-blessed-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]"; + colour=white subject=saint name_la=- comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]"; (* Joseph's own general RG96 walk, finding 31 March already claimed (occupant reports Class1 there, still blocking per [is_blocking]), continues one more day to 1 April -- RG 97-98's "in order": the second @@ -275,7 +289,7 @@ let test_annunciation_joseph_double_transfer_2008 () = check ~msg:"2008-04-01: Joseph's RG96 walk continues past the now-claimed 31 March (RG97-98 'in order')" 2008 4 1 "2008-04-01 tuesday season=paschaltide week=2 slug=joseph-spouse-of-the-bl-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[] in=joseph-spouse-of-the-bl-virgin-mary out=[]" + colour=white subject=saint name_la=- comms=[] in=joseph-spouse-of-the-bl-virgin-mary out=[]" (* ------------------------------------------------------------------ *) (* RG 96 Attamen (a) is CONDITIONAL ("quando est transferendum post @@ -299,15 +313,15 @@ let test_annunciation_exception_not_triggered_general_walk_suffices () = check ~msg:"2057-03-26: general RG96 walk suffices (target before Easter, 22 Apr) -- no Attamen(a) exception" 2057 3 26 "2057-03-26 monday season=lent week=3 slug=annunciation-of-the-blessed-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[ef-lent-3-monday:privileged] in=annunciation-of-the-blessed-virgin-mary out=[]"; + colour=white subject=saint name_la=- comms=[ef-lent-3-monday:privileged] in=annunciation-of-the-blessed-virgin-mary out=[]"; check ~msg:"2007-03-26: general RG96 walk suffices (target before Easter, 8 Apr) -- no Attamen(a) exception" 2007 3 26 "2007-03-26 monday season=passiontide week=1 slug=annunciation-of-the-blessed-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[ef-passiontide-1-monday:privileged] in=annunciation-of-the-blessed-virgin-mary out=[]"; + colour=white subject=saint name_la=- comms=[ef-passiontide-1-monday:privileged] in=annunciation-of-the-blessed-virgin-mary out=[]"; check ~msg:"2012-03-26: general RG96 walk suffices (target before Easter, 8 Apr) -- no Attamen(a) exception" 2012 3 26 "2012-03-26 monday season=passiontide week=1 slug=annunciation-of-the-blessed-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[ef-passiontide-1-monday:privileged] in=annunciation-of-the-blessed-virgin-mary out=[]" + colour=white subject=saint name_la=- comms=[ef-passiontide-1-monday:privileged] in=annunciation-of-the-blessed-virgin-mary out=[]" (* After Easter: 2016 (already pinned above, Easter+8 = 4 April) and 2024 (Easter 31 March, Easter+8 = 8 April). In both, the general walk would @@ -323,7 +337,7 @@ let test_annunciation_exception_triggered_when_walk_would_cross_easter () = (RG26)" 2024 4 8 "2024-04-08 monday season=paschaltide week=2 slug=annunciation-of-the-blessed-virgin-mary rank=class-1 \ - colour=white subject=saint comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]" + colour=white subject=saint name_la=- comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]" (* 2016's own pin (test_annunciation_transfer_inside_holy_week_2016) is the other half of this pair -- not repeated here to avoid asserting the same date twice. *) @@ -342,18 +356,18 @@ let test_precious_blood_transfer_2011 () = check ~msg:"2011-07-01: Sacred Heart (RG91 entry 3) outranks the fixed Precious Blood (entry 11) outright" 2011 7 1 "2011-07-01 friday season=time-after-pentecost week=2 slug=ef-sacred-heart rank=class-1 colour=white subject=temporal \ - comms=[] in=- out=[precious-blood-of-our-lord-jesus-christ->2011-07-04]"; + name_la=- comms=[] in=- out=[precious-blood-of-our-lord-jesus-christ->2011-07-04]"; check ~msg:"2011-07-02: the RG96 walk's first blocked day (Visitation, II class) -- Precious Blood not here" 2011 7 2 "2011-07-02 saturday season=time-after-pentecost week=2 slug=visitation-of-the-blessed-virgin-mary \ - rank=class-2 colour=white subject=saint comms=[processus-and-martinian:ordinary] in=- out=[]"; + rank=class-2 colour=white subject=saint name_la=- comms=[processus-and-martinian:ordinary] in=- out=[]"; check ~msg:"2011-07-03: the RG96 walk's second blocked day (an ordinary Sunday, II class) -- still not here" 2011 7 3 "2011-07-03 sunday season=time-after-pentecost week=3 slug=ef-time-after-pentecost-sunday-3 rank=class-2 \ - colour=green subject=temporal comms=[] in=- out=[]"; + colour=green subject=temporal name_la=- comms=[] in=- out=[]"; check ~msg:"2011-07-04: the first non-I/II-class day (RG96) -- the Precious Blood lands here" 2011 7 4 "2011-07-04 monday season=time-after-pentecost week=3 slug=precious-blood-of-our-lord-jesus-christ \ - rank=class-1 colour=red subject=lord comms=[] in=precious-blood-of-our-lord-jesus-christ out=[]" + rank=class-1 colour=red subject=lord name_la=- comms=[] in=precious-blood-of-our-lord-jesus-christ out=[]" (* ------------------------------------------------------------------ *) (* All Souls falling on a Sunday (register §4, RG96 Attamen (b), primary- @@ -368,11 +382,11 @@ let test_all_souls_on_a_sunday_2025 () = check ~msg:"2025-11-02: All Souls yields to the occurring Sunday (RG91 entry 8), no commemoration (RG94)" 2025 11 2 "2025-11-02 sunday season=time-after-pentecost week=21 slug=ef-time-after-pentecost-sunday-21 rank=class-2 \ - colour=green subject=temporal comms=[] in=- out=[commemoration-of-all-souls->2025-11-03]"; + colour=green subject=temporal name_la=- comms=[] in=- out=[commemoration-of-all-souls->2025-11-03]"; check ~msg:"2025-11-03: All Souls transfers to the following Monday, its sedes propria (RG96 Attamen b)" 2025 11 3 "2025-11-03 monday season=time-after-pentecost week=21 slug=commemoration-of-all-souls rank=class-1 \ - colour=black subject=saint comms=[] in=commemoration-of-all-souls out=[]" + colour=black subject=saint name_la=- comms=[] in=commemoration-of-all-souls out=[]" (* ------------------------------------------------------------------ *) (* Christmas falling on a Sunday (RG91 entry 1: Nativity, Easter, Pentecost @@ -386,7 +400,7 @@ let test_all_souls_on_a_sunday_2025 () = let test_christmas_on_a_sunday_2022 () = check ~msg:"2022-12-25 falling on a Sunday: the Nativity (RG91 entry 1) takes the day outright, no contest" 2022 12 25 - "2022-12-25 sunday season=christmastide week=- slug=ef-nativity rank=class-1 colour=white subject=temporal comms=[] in=- \ + "2022-12-25 sunday season=christmastide week=- slug=ef-nativity rank=class-1 colour=white subject=temporal name_la=- comms=[] in=- \ out=[]" (* ------------------------------------------------------------------ *) @@ -400,18 +414,18 @@ let test_christmas_on_a_sunday_2022 () = let test_holy_thursday_is_white_2026 () = check ~msg:"2026-04-01 (Wednesday of Holy Week): ordinary Passiontide violet (RG128)" 2026 4 1 "2026-04-01 wednesday season=passiontide week=2 slug=ef-passiontide-2-wednesday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[]"; + name_la=- comms=[] in=- out=[]"; check ~msg: "2026-04-02 Holy Thursday: white (RG128(b)'s named exception + RG122's affirmative statement), not \ Passiontide's violet" 2026 4 2 - "2026-04-02 thursday season=passiontide week=2 slug=ef-passiontide-2-thursday rank=class-1 colour=white subject=temporal \ - comms=[] in=- out=[]"; + "2026-04-02 thursday season=passiontide week=2 slug=ef-passiontide-2-thursday rank=class-1 colour=white subject=lord \ + name_la=Feria V in Cena Domini comms=[] in=- out=[]"; check ~msg:"2026-04-03 Good Friday: back to violet (RG128) -- Thursday's white is a one-day exception" 2026 4 3 - "2026-04-03 friday season=passiontide week=2 slug=ef-passiontide-2-friday rank=class-1 colour=violet subject=temporal \ - comms=[] in=- out=[]" + "2026-04-03 friday season=passiontide week=2 slug=ef-passiontide-2-friday rank=class-1 colour=violet subject=lord \ + name_la=Feria VI in Passione et Morte Domini comms=[] in=- out=[]" (* ------------------------------------------------------------------ *) (* Advent/Lent Ember ferias are commemorated when impeded (RG 24: "si vero @@ -431,7 +445,7 @@ let test_ember_ferias_commemorated_when_impeded () = check ~msg:"1900-12-21: Advent Ember Friday, impeded, MUST be commemorated (RG24) and is privileged (RG109e)" 1900 12 21 "1900-12-21 friday season=advent week=3 slug=thomas rank=class-2 colour=red subject=saint \ - comms=[ef-advent-ember-fri:privileged] in=- out=[]"; + name_la=- comms=[ef-advent-ember-fri:privileged] in=- out=[]"; (* 1902-02-22: Lent Ember Saturday (RG91 entry 18, II class) impeded by the Chair of St Peter (II class, universal, entry 16). Same RG24/ RG109(e) mandate. ALSO, ef-holyname-rg110 task: RG 110's own @@ -448,7 +462,7 @@ let test_ember_ferias_commemorated_when_impeded () = AND RG110's Paul companion rides alongside it, uncapped" 1902 2 22 "1902-02-22 saturday season=lent week=1 slug=chair-of-st-peter rank=class-2 colour=white subject=saint \ - comms=[ef-lent-ember-sat:privileged,paul:ordinary] in=- out=[]" + name_la=- comms=[ef-lent-ember-sat:privileged,paul:ordinary] in=- out=[]" let test_iv_class_ferias_never_commemorated () = (* 2026-07-22: an ordinary Time-after-Pentecost feria (Class4, RG91 entry @@ -465,14 +479,14 @@ let test_iv_class_ferias_never_commemorated () = (omitted_has d1 "ef-time-after-pentecost-8-wednesday"); Alcotest.(check string) "2026-07-22: Mary Magdalene observed, no commemoration (RG26)" "2026-07-22 wednesday season=time-after-pentecost week=8 slug=mary-magdalene rank=class-3 colour=white subject=saint \ - comms=[] in=- out=[]" + name_la=- comms=[] in=- out=[]" (describe d1); let d2 = fetch 2026 8 10 in Alcotest.(check bool) "2026-08-10: the displaced IV-class feria is in [omitted], proving RG26 actually fired" true (omitted_has d2 "ef-time-after-pentecost-11-monday"); Alcotest.(check string) "2026-08-10: St Lawrence observed, no commemoration (RG26)" - "2026-08-10 monday season=time-after-pentecost week=11 slug=lawrence rank=class-2 colour=red subject=saint comms=[] in=- \ + "2026-08-10 monday season=time-after-pentecost week=11 slug=lawrence rank=class-2 colour=red subject=saint name_la=- comms=[] in=- \ out=[]" (describe d2) @@ -497,7 +511,7 @@ let test_ii_class_sunday_admits_only_ii_class_commemoration () = (omitted_has d2009 "romanus"); Alcotest.(check string) "2009-08-09: the Sunday observed, no commemoration at all (RG111(b) rank floor)" "2009-08-09 sunday season=time-after-pentecost week=10 slug=ef-time-after-pentecost-sunday-10 rank=class-2 \ - colour=green subject=temporal comms=[] in=- out=[]" + colour=green subject=temporal name_la=- comms=[] in=- out=[]" (describe d2009); let d2026 = fetch 2026 8 9 in Alcotest.(check bool) "2026-08-09: romanus (Class3) is offered and excluded, proving RG111(b) actually fired" @@ -505,7 +519,7 @@ let test_ii_class_sunday_admits_only_ii_class_commemoration () = (omitted_has d2026 "romanus"); Alcotest.(check string) "2026-08-09: the Sunday observed, no commemoration at all (RG111(b) rank floor)" "2026-08-09 sunday season=time-after-pentecost week=11 slug=ef-time-after-pentecost-sunday-11 rank=class-2 \ - colour=green subject=temporal comms=[] in=- out=[]" + colour=green subject=temporal name_la=- comms=[] in=- out=[]" (describe d2026) (* ------------------------------------------------------------------ *) @@ -570,7 +584,7 @@ let test_rg16a_lord_feast_no_sunday_commemoration_2028 () = et privilegiis\" keeps the day a dominica II classis for RG111(b), so Sixtus (Class3) has no standing \ either, oracle-confirmed" "2028-08-06 sunday season=time-after-pentecost week=9 slug=transfiguration-of-our-lord rank=class-2 \ - colour=white subject=lord comms=[] in=- out=[]" + colour=white subject=lord name_la=- comms=[] in=- out=[]" (describe d) (* Holy Family (RG 17(b), scan-verified, docs/research/rules-register.md @@ -629,20 +643,20 @@ let test_holy_family_ordinary_year_2026 () = standing for the day's II-class-only Sunday slot" 2026 1 11 "2026-01-11 sunday season=christmastide week=- slug=ef-time-after-epiphany-sunday-1 rank=class-2 \ - colour=white subject=lord comms=[] in=- out=[]" + colour=white subject=lord name_la=Sanctae Familiae Iesu, Mariae, Ioseph comms=[] in=- out=[]" let test_holy_family_excludes_baptism_2030 () = check ~msg:"2030-01-13: Holy Family on the latest possible date -- RG91 e14 \"primum mobilia\" keeps it \ observed over the fixed Baptism, RG112(a) excludes the Baptism entirely, not merely demotes it" 2030 1 13 "2030-01-13 sunday season=christmastide week=- slug=ef-time-after-epiphany-sunday-1 rank=class-2 \ - colour=white subject=lord comms=[] in=- out=[]" + colour=white subject=lord name_la=Sanctae Familiae Iesu, Mariae, Ioseph comms=[] in=- out=[]" let test_holy_family_earliest_possible_date_2024 () = check ~msg:"2024-01-07: Holy Family on the earliest possible date (Epiphany a Saturday)" 2024 1 7 "2024-01-07 sunday season=christmastide week=- slug=ef-time-after-epiphany-sunday-1 rank=class-2 \ - colour=white subject=lord comms=[] in=- out=[]" + colour=white subject=lord name_la=Sanctae Familiae Iesu, Mariae, Ioseph comms=[] in=- out=[]" (* Most Holy Name of Jesus (RG 17(a), scan-verified, docs/research/rules- register.md §6.2/§4): "festum Ss.mi Nominis Iesu, celebrandum dominica @@ -679,7 +693,7 @@ let test_holy_name_sunday_shape_2026 () = 2026-01-04 row: rank 2, white, title \"Holy Name of Jesus\")" 2026 1 4 "2026-01-04 sunday season=christmastide week=- slug=ef-holy-name-sunday rank=class-2 colour=white \ - subject=lord comms=[] in=- out=[]" + subject=lord name_la=Sanctissimi Nominis Iesu comms=[] in=- out=[]" let test_holy_name_fallback_2029 () = check ~msg:"2029-01-02: Holy Name of Jesus, FALLBACK shape (RG 17(a)'s own \"secus die 2 ianuarii\", the \ @@ -689,7 +703,7 @@ let test_holy_name_fallback_2029 () = here instead -- a real, II-class office simply missing, not merely misnamed" 2029 1 2 "2029-01-02 tuesday season=christmastide week=- slug=ef-holy-name rank=class-2 colour=white \ - subject=lord comms=[] in=- out=[]" + subject=lord name_la=Sanctissimi Nominis Iesu comms=[] in=- out=[]" (* RG 110 (docs/research/rules-register.md §4, Caput XIV), fix round 1 (coordinator findings F1/F2): two golden pins neither existed before this @@ -725,7 +739,7 @@ let test_rg110_june_30_2026 () = commemoration -- missalemeum shows neither (M19, verdict colitur)" 2026 6 30 "2026-06-30 tuesday season=time-after-pentecost week=5 slug=in-commemoratione-sancti-pauli-apostoli \ - rank=class-3 colour=red subject=saint comms=[commemoration-of-st-peter:ordinary] in=- out=[]" + rank=class-3 colour=red subject=saint name_la=- comms=[commemoration-of-st-peter:ordinary] in=- out=[]" let test_rg110_shape_c_2004 () = check ~msg:"2004-02-22: RG 110 shape (c) -- Chair of St Peter itself loses the day to an ordinary \ @@ -734,7 +748,7 @@ let test_rg110_shape_c_2004 () = Sunday, independently confirmed)" 2004 2 22 "2004-02-22 sunday season=septuagesima week=3 slug=ef-septuagesima-sunday-3 rank=class-2 colour=violet \ - subject=temporal comms=[chair-of-st-peter:ordinary,paul:ordinary] in=- out=[]" + subject=temporal name_la=- comms=[chair-of-st-peter:ordinary,paul:ordinary] in=- out=[]" (* 2025-02-02, the other real instance of the SAME pattern -- not a contrasting second direction, per this task's fix round 1 (CRITICAL @@ -767,7 +781,7 @@ let test_purification_on_a_sunday_2025 () = commemoration of the Sunday, oracle-confirmed" 2025 2 2 "2025-02-02 sunday season=time-after-epiphany week=4 slug=purification-of-the-blessed-virgin-mary \ - rank=class-2 colour=white subject=lord comms=[] in=- out=[]" + rank=class-2 colour=white subject=lord name_la=- comms=[] in=- out=[]" (* ------------------------------------------------------------------ *) (* RG 91 entry 24 ("Festa III classis, in calendario Ecclesiae universae @@ -826,15 +840,15 @@ let test_iii_class_feast_wins_class4_feria () = true (omitted_has d1 "ef-easter-2-wednesday"); Alcotest.(check string) "2008-04-02: Francis of Paola (III class, RG91 entry 24) outranks the class-4 feria" - "2008-04-02 wednesday season=paschaltide week=2 slug=francis-of-paola rank=class-3 colour=white subject=saint comms=[] \ + "2008-04-02 wednesday season=paschaltide week=2 slug=francis-of-paola rank=class-3 colour=white subject=saint name_la=- comms=[] \ in=- out=[]" (describe d1); check ~msg:"2008-04-04: Isidore of Seville (III class) outranks the class-4 Paschaltide feria, same shape" 2008 4 4 - "2008-04-04 friday season=paschaltide week=2 slug=isidore-of-seville rank=class-3 colour=white subject=saint comms=[] in=- \ + "2008-04-04 friday season=paschaltide week=2 slug=isidore-of-seville rank=class-3 colour=white subject=saint name_la=- comms=[] in=- \ out=[]"; check ~msg:"2008-04-05: Vincent Ferrer (III class) outranks the class-4 Paschaltide feria, same shape" 2008 4 5 - "2008-04-05 saturday season=paschaltide week=2 slug=vincent-ferrer rank=class-3 colour=white subject=saint comms=[] in=- \ + "2008-04-05 saturday season=paschaltide week=2 slug=vincent-ferrer rank=class-3 colour=white subject=saint name_la=- comms=[] in=- \ out=[]"; let d4 = fetch 2038 3 6 in Alcotest.(check bool) @@ -844,15 +858,15 @@ let test_iii_class_feast_wins_class4_feria () = Alcotest.(check string) "2038-03-06: Sts Perpetua and Felicity (III class, RG91 entry 24) outrank the class-4 feria; RED per their \ own martyrs' colour, not the season's violet" - "2038-03-06 saturday season=septuagesima week=2 slug=sts-felicitas-perpetua rank=class-3 colour=red subject=saint comms=[] \ + "2038-03-06 saturday season=septuagesima week=2 slug=sts-felicitas-perpetua rank=class-3 colour=red subject=saint name_la=- comms=[] \ in=- out=[]" (describe d4); check ~msg:"2038-03-08: John of God (III class) outranks the class-4 Septuagesima feria, same shape" 2038 3 8 - "2038-03-08 monday season=septuagesima week=3 slug=john-of-god rank=class-3 colour=white subject=saint comms=[] in=- \ + "2038-03-08 monday season=septuagesima week=3 slug=john-of-god rank=class-3 colour=white subject=saint name_la=- comms=[] in=- \ out=[]"; check ~msg:"2038-03-09: Frances of Rome (III class) outranks the class-4 Septuagesima feria, same shape" 2038 3 9 - "2038-03-09 tuesday season=septuagesima week=3 slug=frances-rome rank=class-3 colour=white subject=saint comms=[] in=- \ + "2038-03-09 tuesday season=septuagesima week=3 slug=frances-rome rank=class-3 colour=white subject=saint name_la=- comms=[] in=- \ out=[]" let suite = diff --git a/test/test_temporal_ef.ml b/test/test_temporal_ef.ml index f341533..a979700 100644 --- a/test/test_temporal_ef.ml +++ b/test/test_temporal_ef.ml @@ -732,6 +732,85 @@ let test_holy_name_fallback_anchor_present_and_erosion_is_caught () = Alcotest.(check string) "sanity: temporal itself is unaffected by the anchors-list erosion" expected_slug (slug_of expected_date) +(* Gap 1 (ef-triduum-litanies, docs/research/rules-register.md, "the Sacred + Triduum has no proper office"): the Missal's own Mass-propers headings for + Holy Thursday/Good Friday/Holy Saturday, both photographic scans, word for + word (missale-romanum-1962.pdf and "Missale Romanum 1962_text.pdf", + corroborated by the electronic transcription's own table-of-contents-style + listing at the identical three headings -- three-way agreement, no + scan-vs-transcription conflict to adjudicate): "FERIA QUINTA IN CENA + DOMINI" / running header "Feria V in Cena Domini"; "FERIA SEXTA / IN + PASSIONE ET MORTE DOMINI"; "SABBATO SANCTO". The slug stays the generic + Passiontide ferial one (RG 91 entry 2 already identifies the Triduum + structurally, off the day's own Easter offset and rank -- + {!Rite_ef.Precedence_ef.band}'s own entry-2 branch -- never off the slug, + so renaming it would touch precedence for no reason and would break the + lectio differential's own slug mapping for these three lectionary keys); + the missing IDENTITY is carried in [names], the same treatment RG + 17(b)/(a) (Holy Family/Holy Name) already established -- Latin, not + English, for the same zero-circularity reason those two entries give + (would otherwise read the oracle this exact axis is compared against). + + [subject] is ALSO set to [Lord] here, going further than Holy Family/Holy + Name's own precedent strictly required (they needed it because + {!Rite_ef.Precedence_ef.band}'s entry 14 reads [subject] to outrank a + colliding fixed feast). The Triduum has no such live need: entry 2 is + decided purely by [rank]/Easter-offset, never [subject] -- confirmed by + reading {!Rite_ef.Precedence_ef.band}'s own entry-2 branch, which tests + neither. Tagged anyway because it is simply true (the Last Supper, the + Passion and Death, the entombment are textbook mysteries of the Lord) and + safe: {!Rite_ef.Precedence_ef.disposition}'s own RG 112(a) branch (Lord vs + Lord) only fires when BOTH sides are tagged [Lord], and no [Lord]-subject + sanctoral entry anywhere in data/ef/sanctoral.sexp has a FIXED civil date + inside Holy Week's own movable range (earliest 19 March, latest 24 April + -- the register's own subject audit lists exactly six [Lord]-tagged + entries, all fixed in January, February, August, September or November); + any [Class1] sanctoral entry that DOES land there (e.g. a transferred + Annunciation) reaches {!Rite_ef.Precedence_ef.disposition}'s EARLIER, + subject-blind "I class, not a Sunday -> Transfer" branch first, so RG + 112(a)'s own branch is never reached for it regardless of this tag. + Measured empirically too: this task's own full 1583-9999 blast-radius + sweep shows no [observed]/[commemorations]/[transferred_*] difference + traceable to this tag anywhere in the domain. *) +let test_sacred_triduum_identity () = + (* 2026: Easter 5 April, so Holy Thursday/Good Friday/Holy Saturday are + 2/3/4 April. *) + Alcotest.(check string) "2026-04-02 Holy Thursday: slug stays the generic ferial key" + "ef-passiontide-2-thursday" (slug_of (d 2026 4 2)); + Alcotest.(check bool) "2026-04-02 Holy Thursday: subject Lord" true + (subject_of (d 2026 4 2) = Sub.Lord); + Alcotest.(check (option string)) "2026-04-02 Holy Thursday: Latin name, both photographic scans verbatim" + (Some "Feria V in Cena Domini") (name_la_of (d 2026 4 2)); + Alcotest.(check string) "2026-04-03 Good Friday: slug stays the generic ferial key" + "ef-passiontide-2-friday" (slug_of (d 2026 4 3)); + Alcotest.(check bool) "2026-04-03 Good Friday: subject Lord" true + (subject_of (d 2026 4 3) = Sub.Lord); + Alcotest.(check (option string)) "2026-04-03 Good Friday: Latin name, both photographic scans verbatim" + (Some "Feria VI in Passione et Morte Domini") (name_la_of (d 2026 4 3)); + Alcotest.(check string) "2026-04-04 Holy Saturday: slug stays the generic ferial key" + "ef-passiontide-2-saturday" (slug_of (d 2026 4 4)); + Alcotest.(check bool) "2026-04-04 Holy Saturday: subject Lord" true + (subject_of (d 2026 4 4) = Sub.Lord); + Alcotest.(check (option string)) "2026-04-04 Holy Saturday: Latin name, both photographic scans verbatim" + (Some "Sabbato Sancto") (name_la_of (d 2026 4 4)); + (* Neighbouring days carry no name/subject override -- the tag is exactly + three days wide, not the whole Passiontide-2 week. *) + Alcotest.(check (option string)) "2026-04-01 (Wednesday of Holy Week): no Latin name" + None (name_la_of (d 2026 4 1)); + Alcotest.(check bool) "2026-04-01 (Wednesday of Holy Week): subject stays temporal" true + (subject_of (d 2026 4 1) = Sub.Temporal); + Alcotest.(check (option string)) "2026-04-05 Easter Sunday: no Latin name from this branch" + None (name_la_of (d 2026 4 5)); + (* A second, independent year (1666: the latest possible Easter, 25 April, + already this file's own Easter-extreme witness elsewhere) -- proves the + mechanism generalises off [days_between easter d], not hand-pinned to + 2026's own civil dates. Holy Thursday/Good Friday/Holy Saturday are + 22/23/24 April 1666. *) + Alcotest.(check (option string)) "1666-04-22 Holy Thursday (latest-Easter year): Latin name still fires" + (Some "Feria V in Cena Domini") (name_la_of (d 1666 4 22)); + Alcotest.(check bool) "1666-04-22 Holy Thursday: subject Lord" true + (subject_of (d 1666 4 22) = Sub.Lord) + let test_totality () = (* Every day of 2026 yields an office without raising. Not a slug re-validation -- Slug.t is a private string validated on construction, @@ -765,6 +844,8 @@ let suite_extra = Alcotest.test_case "ember days" `Quick test_ember_days; Alcotest.test_case "rogations" `Quick test_rogations; Alcotest.test_case "colours" `Quick test_colours; + Alcotest.test_case "sacred triduum identity (RG 91 entry 2, Gap 1)" `Quick + test_sacred_triduum_identity; Alcotest.test_case "christmastide feria slugs" `Quick test_christmastide_feria_slugs; Alcotest.test_case "named days carry their week" `Quick test_named_days_carry_their_week; Alcotest.test_case "totality" `Quick test_totality; -- cgit v1.3