(* Task 17: golden pins -- validation layer 5 of the design spec's five (colitur CLAUDE.md "Validation" section; layers 1-4 -- Types, Property, the lectio differential, the missalemeum oracle -- are already built and green: test_validate.ml, test_differential.ml, test_oracle.ml). *** THE ONE RULE THIS FILE IS BUILT AROUND *** A golden test blesses whatever it is given. Every other layer derives its expectation from something independent of colitur's own output -- an invariant, a sibling engine, a published calendar oracle. This layer's expectation comes from ME, so every literal string below was checked by hand, against sources OUTSIDE this codebase, BEFORE it was typed in here -- never copied from a `colitur day` run and then rationalised: 1. The three Easter dates this file pins (1598-03-22, 1666-04-25, 2038-04-25) were independently computed by hand using the standard Gauss/Meeus Gregorian Easter algorithm (the same algorithm register §0's "first Sunday on/after the ecclesiastical full moon on/after 21 March" reduces to), NOT read off Computus.gregorian_easter or the CLI. All three matched colitur's own output exactly on the first attempt. 2. EVERY weekday asserted below was independently cross-checked against `date -d +%A` (GNU coreutils, glibc's own proleptic- Gregorian calendar arithmetic -- a completely separate implementation from anything in this repository) before being written into a literal string. All matched. 3. Every precedence/transfer/commemoration outcome was traced by hand against its RG citation (quoted or paraphrased in each test's own comment) and against the actual `band`/`disposition`/`admit`/ `transfer_target` logic in precedence_ef.ml, not merely observed to "look plausible". Where the primary text alone does not fully settle an outcome (the 2008 Annunciation/Joseph tie, see that test's own comment), this is said explicitly rather than papered over with a confident-sounding citation. *** WHY [describe] BUILDS ONE STRING PER DAY *** Every assertion below compares ONE formatted line against a single expected literal, rather than five or six separate field checks. This is deliberate: a one-line diff on failure still names the day (it is the first token) and shows exactly which field changed (Alcotest's own diff highlights the differing substring) -- "prove the pins have teeth" in the brief's own words -- while keeping each test's body to one literal per date instead of five, which is what makes 30-odd pinned dates reviewable at all. [describe]'s own five components (season/week/slug/rank/colour, commemorations, transferred_in, transferred_out) are exactly the fields {!Colitur_kernel.Liturgical_day.t} promises never to lose (that type's own doc comment) -- nothing is cherry-picked to make a case look cleaner than it is. *) module Cal = Colitur_kernel.Calendar module Layer = Colitur_kernel.Layer module Overlay = Colitur_kernel.Overlay module LD = Colitur_kernel.Liturgical_day module Slug = Colitur_kernel.Slug module Date = Colitur_kernel.Date module Cel = Colitur_kernel.Celebration module Colour = Colitur_kernel.Colour module Citation = Colitur_kernel.Citation module Temporal = Colitur_kernel.Temporal module Prec = Colitur_kernel.Precedence module V = Rite_ef.Vocab_ef (* Same relative paths every other suite in this directory uses (dune test runs from _build/default/test/). *) let sanctoral_path = "../data/ef/sanctoral.sexp" let adjustments_path = "../data/ef/adjustments.sexp" let lectionary_path = "../data/ef/lectionary.sexp" let commons_path = "../data/ef/commons.sexp" (* Loaded once at module init, same convention test_validate.ml's own [real_ef_layer] uses (not test_oracle.ml/test_differential.ml's per-test-case reload, which recomputes a whole 46-year or 2-year sweep per call for reasons specific to those files -- loading the immutable layer itself has no such per-call cost and nothing here mutates it). *) let real_ef_layer = match Layer.load V.rank_of_sexp sanctoral_path with | Error e -> failwith (Printf.sprintf "%s: failed to load: %s" sanctoral_path e) | Ok layer -> ( match Overlay.load V.rank_of_sexp adjustments_path with | Error e -> failwith (Printf.sprintf "%s: failed to load: %s" adjustments_path e) | Ok overlay -> let layer, diagnostics = Overlay.apply layer overlay in if diagnostics <> [] then failwith (Printf.sprintf "unexpected overlay diagnostics: %s" (String.concat "; " (List.map Overlay.diagnostic_to_string diagnostics))); layer) (* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) -- caller-supplied, same as [real_ef_layer] above. *) let real_ef_lectionary = match Colitur_kernel.Lectionary.load lectionary_path with | Error e -> failwith (Printf.sprintf "%s: failed to load: %s" lectionary_path e) | Ok l -> l (* The Commons (data/ef/commons.sexp) travel the same caller-supplied seam as the lectionary above, and [~commons] is required rather than defaulted so that no caller can silently run with none. CORRECTED, Task 9 fix round 1 (coordinator review): this used to claim "nothing in layers 3-5 compares reading citations" -- stale since Task 8 (layer 3) and Task 9 (layer 4). THIS layer (5, golden pins) is the one that still does not: this file's own [describe] carries no citation field at all, so a rite quietly missing its Commons would still be invisible here specifically, even though layers 3/4 would now catch it. Loaded here even where this file asserts nothing about readings, so that the rite under test is the same one bin/main.ml assembles. *) let real_ef_commons = match Rite_ef.Lectionary_ef.Commons.load commons_path with | Error e -> failwith (Printf.sprintf "%s: failed to load: %s" commons_path e) | Ok c -> c let real_ef_rite = Rite_ef.context ~lectionary:real_ef_lectionary ~commons:real_ef_commons let mk y m d = match Date.make ~year:y ~month:m ~day:d with Ok t -> t | Error e -> failwith e (* [Cal.day] recomputes its whole liturgical year on every call (calendar.mli -- "pure, no cache"); acceptable here, same as test_rite_ef.ml's own use of [Cal.year] for a handful of dates, not a hot loop. *) let fetch y m d = Cal.day real_ef_rite real_ef_layer (mk y m d) 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 original Holy Family pins (2026-01-11, 2024-01-07) were byte-identical before and after temporal_ef.ml's own fix -- reverting the feature failed only the 2030-01-13 collision pin, because [describe] omitted the ONE field the change touches on an ordinary (non-collision) year. Vacuity flavour #1 ("an assertion already true before the code under test ran"), not #8 ("promoted from actual output") -- the OTHER nine fields' values were independently sourced and remain so; only this tenth was missing. 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. 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 let comms = List.map (fun (c, p) -> Printf.sprintf "%s:%s" (slug_s c) (privilege_s p)) day.LD.commemorations |> List.sort compare |> String.concat "," in let tin = match day.LD.transferred_in with None -> "-" | Some c -> slug_s c in let tout = 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 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) (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)) (* ---- Task 10: the reading citations ---- A SEPARATE formatter rather than widening [describe] itself, and the reason is this file's own opening rule, not convenience. Widening [describe] would invalidate all ~30 expected literals above at once, and the only practical way to restore them would be to run the suite and paste back whatever colitur printed -- "copied from a `colitur day` run and then rationalised", the exact thing the header forbids. Restoring them HONESTLY would mean hand-verifying 30 further Masses against the scans, which is a task of its own and not this one. So the trade is stated rather than hidden: the pins above stay citation-blind, and the pins below carry citations for one day per chain step, every literal hand-verified against the photographic scans BEFORE being typed here (each pin's own comment carries its scan line numbers). That division is defensible because layer 2 now covers what breadth would have bought: {!Colitur_kernel.Validate}'s own citation checks assert the SHAPE of every day's citations in every year 1583-9999 -- far more days than 30 pins could -- so what layer 5 still owes is specific VALUES on the distinct routes, which is exactly what these six are. *) let describe_readings (day : (V.season, V.rank) LD.t) = let part_ref p = match List.find_opt (fun (c : Citation.t) -> c.Citation.part = p) day.LD.citations with | Some c -> c.Citation.reference | None -> "-" in Printf.sprintf "%s slug=%s first=%s gospel=%s" (Date.to_iso8601 day.LD.date) (slug_s day.LD.observed) (part_ref Citation.First) (part_ref Citation.Gospel) let check_readings ~msg y m d expected = Alcotest.(check string) msg expected (describe_readings (fetch y m d)) let omitted_has (day : (V.season, V.rank) LD.t) slug = List.exists (fun (c, _) -> slug_s c = slug) day.LD.omitted (* ------------------------------------------------------------------ *) (* Easter extremes (register §0; independently Gauss-computed, see file header point 1). extreme_years in test_validate.ml already pins that 1598/1666 are the true earliest/latest within 1583..2500 -- this file pins what the RESOLVED DAY looks like there, not merely that Easter lands on the expected date. *) (* ------------------------------------------------------------------ *) (* 1598: earliest Gregorian Easter possible, 22 March -- hand-verified via Gauss's algorithm (a = 2, b = 15, c = 98, ..., h = 0, l = 0, m = 0 -> 22 March), independent of Computus.gregorian_easter. RG 76 (Paschaltide begins with the Vigil Mass) + RG 91 entry 1 (Easter Sunday, I class) + RG 119(b) (white from the Vigil Mass) fix season/rank/colour; the day before (Holy Saturday, still Passiontide, violet per RG 128) is pinned alongside it to prove the season boundary itself falls in the right 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=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 name_la=- comms=[] in=- \ out=[]" (* 1666: latest Gregorian Easter possible, 25 April -- hand-verified via Gauss's algorithm (a = 13, b = 16, c = 66, ..., h = 29, l = 5, m = 0 -> 25 April). Same citations as 1598 above. ef-major-litanies task: 25 April = Easter Sunday is RG 80's own FIRST trigger condition ("si vero eo die occurrit dominica Paschatis... transferuntur in sequentem feriam III") -- this pin, already the project's own hand-verified latest-Easter witness, now ALSO carries the transfer this rule requires: [major-litanies] departs 25 April for 27 April (Easter+2, "the following Tuesday" -- Precedence_ef.transfer_ target's own Litanies branch has the full citation). Nothing else about this day changes: [observed]/[comms]/[in] are exactly as before, proving the Litanies departure is additive, not disruptive, to the day Easter itself owns outright. *) 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=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 name_la=- comms=[] in=- \ out=[major-litanies->1666-04-27]"; (* The transfer's own target, positively pinned (not merely inferred from [out] above): an ordinary Easter-octave Tuesday, I class, white (RG 119 -- white "a Missa Vigiliae paschalis usque ad Missam vigiliae Pentecostis"), with the Litanies as its own sole, privileged commemoration (RG 109(f); RG 111(a), "I class: none save one privileged" -- {!PE.admit}'s own [Class1] case). No [transferred_in] printed: [Liturgical_day.transferred_in] only ever names a candidate that went on to WIN the day (calendar.ml's own [build_day]), and the Litanies structurally never can (RG 81, Commemoration_only) -- this is the SAME asymmetry {!Colitur_kernel.Calendar}'s own [settled_at] fix (this task) exists to get right on the OTHER side of the ledger. *) check ~msg:"1666-04-27 Easter+2: the Litanies' own transfer target, commemorated and privileged" 1666 4 27 "1666-04-27 tuesday season=paschaltide week=1 slug=ef-easter-1-tuesday rank=class-1 colour=white subject=temporal \ name_la=- comms=[major-litanies:privileged] in=- out=[]" (* 2038: the brief's "late modern case" -- Easter also 25 April (Gauss- verified: a = 5, b = 20, c = 38, ..., h = 29, l = 5, m = 0 -> 25 April, the SAME extreme as 1666, reached independently), chosen because it is a near-term year rather than a 17th-century one. ORIGINAL EXCLUSION, now RESOLVED (ef-rebootstrap, 2026-08-12): this comment used to say 2038-03-06 (+sts-felicitas-perpetua), 2038-03-08 (+john-of-god) and 2038-03-09 (+frances-rome) were deliberately left unpinned because they were WRONG -- three sanctoral entries bootstrapped from lectio carried a `Commemoration_only` status that should have been a real III-class Feast. That defect was in lectio's own generator, not fixable without touching lectio; lectio's generator has SINCE been fixed (source SHA-256 6a25e634... -> 1b303ef2...) and colitur re-bootstrapped from it, so this specific exclusion reason no longer holds. These three dates, plus three more of the same shape (2008-04-02/04/05), are now pinned below in [test_iii_class_feast_wins_class4_feria] -- the deferred pin this comment always pointed at, not a new finding. Kept as a temporal-cycle-only test regardless (the two concerns -- Easter-extreme arithmetic and a sanctoral occurrence rule -- stay separate pins even though nothing forces that any more). *) (* ef-major-litanies task: 2038 is this file's own worked example for the OTHER RG 80 trigger shape checked elsewhere in this task (Easter Monday = 25 April, e.g. 2011) landing on the identical target (Easter+2) -- here Easter SUNDAY itself is 25 April, so the "following Tuesday" is two days later, 27 April, not one; both shapes converge on Easter+2, never on Easter+1 or Easter+3 (precedence_ef.ml's own [transfer_target] Litanies branch has the full RG 80 citation and the arithmetic for both shapes). *) 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=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 name_la=- comms=[] in=- \ out=[major-litanies->2038-04-27]"; check ~msg:"2038-04-27 Easter+2: the Litanies' own transfer target, commemorated and privileged" 2038 4 27 "2038-04-27 tuesday season=paschaltide week=1 slug=ef-easter-1-tuesday rank=class-1 colour=white subject=temporal \ name_la=- comms=[major-litanies:privileged] in=- out=[]" (* ------------------------------------------------------------------ *) (* Annunciation transfer, 25 March inside Holy Week (register §4, RG 96 Attamen (a)). 2016: Easter = 27 March (Gauss-independent of this file's own concern -- already covered by extreme-year hand-checks above; 2016 is an ordinary year, trusted via the property sweep + the weekday cross-check below), so 25 March 2016 falls on GOOD FRIDAY itself -- literally inside Holy Week, not merely "impeded by the Easter octave" the way the 1598/2008/1666 cases are. Independently confirmed: `date -d 2016-03-25 +%A` = Friday, `date -d 2016-03-27 +%A` = Sunday (Easter). *) let test_annunciation_transfer_inside_holy_week_2016 () = (* RG 91 entry 2 (Sacred Triduum) outranks entry 11 (an ordinary universal I-class feast) outright -- Good Friday wins, Annunciation is Transfer-disposed (RG 95: only I-class feasts transfer). RG 23 (I-class ferias admit no commemoration except one privileged) leaves nothing on the day itself: register's own note on RG 23 says this branch "never 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=black 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 name_la=- comms=[] in=annunciation-of-the-blessed-virgin-mary out=[]" (* ------------------------------------------------------------------ *) (* 2008: the double transfer (register §4, "cases worth adding"). Easter = 23 March 2008 (trusted via the property sweep, not independently Gauss-checked a fourth time -- the algorithm is already hand-verified above; what this case adds is the TWO-CANDIDATE collision, not a fourth Easter-date check). Independently confirmed: `date -d 2008-03-19 +%A` = Wednesday, `-03-31` = Monday, `-04-01` = Tuesday. *) let test_annunciation_joseph_double_transfer_2008 () = (* St Joseph (19 March, I class, universal, band 11 -- same table entry as the Annunciation) falls on Wednesday of Holy Week (RG 91 entry 7: an I-class feria, band 7, above 11) -- impeded, Transfer-disposed. *) 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 \ 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 for BOTH: the Annunciation's own general walk from 26 March would cross the Easter octave and land past Easter, so its exception fires -- Easter + 8 = 23 Mar + 8 = 31 March, its NAMED sedes propria. Joseph has no such named exception; its own general walk (from 20 March) also crosses the octave and, absent Annunciation, would land on the SAME 31 March. WEAKER-THAN-IT-LOOKS, stated honestly: RG 97-98's plain text ("the higher in the table is kept") does not itself distinguish two candidates tied at the SAME table entry (11) the way it does for a genuine dignity difference -- the engine breaks this specific tie by slug (calendar.ml's own [compare_deferred]: alphabetical, an engineering convention, not itself an RG citation), and "annunciation-of-the-blessed-virgin-mary" < "joseph-spouse-of-the-bl- virgin-mary" is exactly why Annunciation claims 31 March first in [place_transfers]'s per-round sort. A textual argument beyond the bare tie-break does exist -- the Annunciation's own Attamen clause names its target as a "sedes propria" (proper seat), a positively-assigned day, where Joseph is merely wherever the generic RG96 search happens to land -- but this is this report's own reading of the primary text, not something the register states outright, so it is offered as corroboration, not as the citation carrying the outcome. *) 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 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 I-class candidate to reach an already-occupied target keeps searching rather than displacing the first. *) 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 name_la=- comms=[] in=joseph-spouse-of-the-bl-virgin-mary out=[]" (* ------------------------------------------------------------------ *) (* RG 96 Attamen (a) is CONDITIONAL ("quando est transferendum post Pascha") -- pinning both sides so the condition itself, not merely the exception's existence, is under test. All six weekdays independently confirmed via `date -d`. *) (* ------------------------------------------------------------------ *) (* Before Easter: 2057 (Easter 22 Apr), 2007 and 2012 (both Easter 8 Apr). In each, 25 March is a Sunday impeding the Annunciation (Lent III in 2057; Passion Sunday, Dominica I Passionis, in 2007/2012), and the GENERAL RG96 walk lands on 26 March -- an ordinary III-class feria, band 22/25, well before Easter -- so the condition never fires: no named exception, just the plain walk. Each arrival day's own displaced feria is RG25/RG109(e)-privileged (an ordinary Lent/Passiontide feria, impeded, must be commemorated) -- a second, independent confirmation of the RG24/25/RG109(e) mandate this file also pins directly below at 1900/1902, in a different code path (an ARRIVING transferred feast's displaced office, not a plain sanctoral winner's). *) 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 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 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 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 cross Easter, so Attamen(a) fires and lands the feast on the Monday after Low Sunday exactly. Both arrival days are Paschaltide-2 (Class4 ferias) -- RG26 (IV-class ferias never commemorated), so unlike the "before" trio above, no commemoration is left behind; a second, independent confirmation of RG26 in yet another code path. *) let test_annunciation_exception_triggered_when_walk_would_cross_easter () = check ~msg: "2024-04-08: Easter+8 (Easter=31 Mar): RG96 Attamen(a) fires, arrival day is Class4 so no commemoration \ (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 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. *) (* ------------------------------------------------------------------ *) (* 2011-07-04, the Precious Blood (register §4/§6, differential C10). Sacred Heart (Easter + 68, RG 91 entry 3) coincides with the fixed 1 July feast of the Most Precious Blood (entry 11) in 2011 (Easter = 24 April, so Easter + 68 = 1 July). Entry 3 outranks entry 11 outright (RG 97-98: the higher in the table is kept) -- no tie, unlike the 2008 case above. The general RG96 walk from 2 July must skip Visitation (2 July, II class, entry 19) and the ordinary Sunday (3 July, entry 15, II class) before landing on 4 July, an ordinary Class4 feria. All four weekdays independently confirmed via `date -d`. *) 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 \ 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 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 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 name_la=- comms=[] in=precious-blood-of-our-lord-jesus-christ out=[]" (* ------------------------------------------------------------------ *) (* All Souls falling on a Sunday (register §4, RG96 Attamen (b), primary- source-verified: "quando occurrit cum dominica, transfertur ... in feriam II sequentem"). 2025: All Souls (2 Nov) falls on an ordinary Sunday. Weekdays independently confirmed via `date -d`. *) let test_all_souls_on_a_sunday_2025 () = (* RG91 entry 8's own parenthetical ("yields to an occurring Sunday") plus Attamen (b): the Sunday is simply observed, and RG94 ("a fixed-day commemoration is not carried with a transferred feast") means the transferred All Souls leaves nothing behind on the Sunday itself. *) 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 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 name_la=- comms=[] in=commemoration-of-all-souls out=[]" (* ------------------------------------------------------------------ *) (* Christmas falling on a Sunday (RG91 entry 1: Nativity, Easter, Pentecost are I class WITH THEIR OWN OCTAVE, listed first in the whole table -- temporal_ef.ml assigns 25 December the Nativity office unconditionally, so unlike a Feast of the Lord merely REPLACING an occurring Sunday (RG 16(a), register §6), there is no Sunday-of-Advent/-per-annum candidate to even contest here: 25 December is never, in the EF temporal cycle, an "ordinary Sunday" in the first place. 2022: `date -d 2022-12-25 +%A` = Sunday, independently confirmed. *) 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 name_la=- comms=[] in=- \ out=[]" (* ------------------------------------------------------------------ *) (* Holy Thursday is white (register §3b, RG 128(b) + RG 122, Task 16) while the surrounding Passiontide days stay violet -- the case the brief flags because colitur and lectio previously AGREED on violet (both wrong), so the lectio differential was structurally incapable of ever catching this; only a golden pin (or the missalemeum oracle, layer 4) can. 2026: Easter 5 April (trusted via the property sweep). Weekdays independently confirmed via `date -d`. *) 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 \ 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=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=black 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 impediuntur, commemorari debent" -- MUST be commemorated) while IV-class ferias never are (RG 26: "quae nunquam commemorantur") -- the fix-round-1 F1/F2 finding, a Critical bug caught late precisely because no golden pin existed for it before now. Weekdays independently confirmed via `date -d`. *) (* ------------------------------------------------------------------ *) let test_ember_ferias_commemorated_when_impeded () = (* 1900-12-21: Advent Ember Friday (RG91 entry 18, II class) impeded by St Thomas (II class, universal, entry 16 -- Thomas outranks an II-class feria only because entry 16 < 18 in the table). RG24 makes the Ember feria's commemoration MANDATORY, and RG109(e) (corrected, fix round 1) makes it PRIVILEGED, not merely eligible. *) 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 \ 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 inseparable Peter/Paul commemoration -- "in Officio ... S. Petri semper fit commemoratio S. Pauli" -- fires unconditionally whenever [chair-of-st-peter] is observed, uncapped by RG 111's own admission count, so `+paul` now rides alongside the Ember feria's own commemoration rather than being displaced by it (precedence_ef.ml's own [rg110_additions]). This pin's own [ef-lent-ember-sat:privileged] half is UNCHANGED from before this task -- only [paul:ordinary] is new, confirming RG 110 adds a genuinely SEPARATE, uncapped slot rather than competing for the Ember feria's own privileged one. CORRECTED (ef-sanctoral-audit, 2026-08-14): [chair-of-st-peter]'s own colour was `white` here, matching the pre-audit bootstrap -- WRONG, RG 124(b) ("XVIII - De coloribus paramentorum", both photographic scans, word for word): red is used "in Officio et Missa de festis... Sanctorum Apostolorum et Evangelistarum, in eorum die natalicio, excepto festo S. Ioannis (27 decembris)" -- red for an Apostle's own feast day, no exception for a Chair feast. Fixed via data/ef/adjustments.sexp's own `Edit chair-of-st-peter ((Set_colour Red))`; this pin now asserts the corrected value, catching a regression back to the old one either way. *) check ~msg:"1902-02-22: Lent Ember Saturday, impeded, MUST be commemorated (RG24) and is privileged (RG109e) -- \ AND RG110's Paul companion rides alongside it, uncapped -- AND Chair of St Peter is WHITE, \ named by date in RG120(f)'s own enumeration of white ('Cathedrae S. Petri (22 februarii)'). \ THIS PIN WAS RIGHT AND WAS EDITED TO ACCOMMODATE A WRONG CHANGE: the ef-sanctoral-audit task \ set it to red on RG124(b), whose 'in eorum die natalicio' qualifier does not reach the Chair, \ and rewrote this assertion rather than treating its failure as evidence. Restored by the \ fix-round review. A pin that resists a change is evidence, not an obstacle" 1902 2 22 "1902-02-22 saturday season=lent week=1 slug=chair-of-st-peter rank=class-2 colour=white subject=saint \ 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 28) impeded by St Mary Magdalene (III class). RG26 ("IV-class ferias are NEVER commemorated") means the displaced feria is dropped outright -- present in [omitted], never in [commemorations]. Asserting only "comms=[]" would be vacuous if there had been no losing candidate at all (one of this project's own catalogued vacuity flavours); the [omitted_has] check below proves a real candidate existed and was actively excluded, not merely absent. *) let d1 = fetch 2026 7 22 in Alcotest.(check bool) "2026-07-22: the displaced IV-class feria is in [omitted], proving RG26 actually fired" true (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 \ 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 name_la=- comms=[] in=- \ out=[]" (describe d2) (* ------------------------------------------------------------------ *) (* RG 111(b): a II-class SUNDAY admits only a commemoration "de festo II classis" -- a rank restriction, not "the best available ordinary candidate". 9 August falling on a Sunday: `romanus` (Class3, commemoration-only, register §6 notes his very existence is questionable, but that is irrelevant here -- RG111(b) excludes him on RANK alone, regardless of that open question) has no standing for the day's single slot. The brief names four recurring years (2009, 2015, 2020, 2026); two are pinned here (2009 for an older-era instance, 2026 for a current one) -- 2015/2020 were hand-checked via the CLI and found identical in shape (same slug family, same `romanus` exclusion, only the week number differs), so pinning all four would repeat the same assertion four times without exercising a different code path; rejected as duplicative. *) let test_ii_class_sunday_admits_only_ii_class_commemoration () = let d2009 = fetch 2009 8 9 in Alcotest.(check bool) "2009-08-09: romanus (Class3) is offered and excluded, proving RG111(b) actually fired" true (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 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" true (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 name_la=- comms=[] in=- out=[]" (describe d2026) (* ------------------------------------------------------------------ *) (* RG 16(a) (register §6.0, Caput III "De Dominicis", primary text quoted in this task's own report): "festum Domini I aut II classis, in dominica II classis occurrens, ... de dominica, proinde, nulla fit commemoratio" -- a Feast of the Lord, I or II class, impeding a II-class Sunday, takes the Sunday's own place with no commemoration of the Sunday at all, unlike every OTHER impeded II-class Sunday (RG 109(a)/RG 111(b), the [test_ii_class_sunday_admits_only_ii_class_commemoration] pin above). Two real dates, both directions, exactly the pair the task brief asks for. *) (* ------------------------------------------------------------------ *) (* 2028-08-06: the Transfiguration (6 Aug, II class, calendarium "IN TRANSFIGURATIONE D. N. I. C.") falls on an ordinary Time-after-Pentecost Sunday. `date -d 2028-08-06 +%A` = Sunday, independently confirmed. Also the exact date register §6.0's own reproduction names as a live instance of the bug this pin closes -- before this fix `colitur day` admitted "+ef-time-after-pentecost-sunday-9" here. CORRECTED, fix round 1 (IMPORTANT finding, item 2): this pin used to expect Pope Sixtus II et al. (6 August's own unrelated Class3 saint, Commemoration_only) admitted as an ordinary commemoration in the freed slot -- promoted from `colitur day`'s own actual output without consulting either the primary text or the oracle first (the exact vacuous-pin flavour the review caught, and this file's own header warns against). Re-derived properly this time: - PRIMARY TEXT: RG 16(a) itself says the winning Feast of the Lord holds the Sunday's place cum omnibus iuribus et privilegiis -- WITH ALL the Sunday's own rights and privileges. RG 111(b) is one of those: in dominicis II classis, una tantum admittitur commemoratio, SCILICET DE FESTO II CLASSIS -- a Sunday's own slot is reserved for a Class2 candidate specifically. The day is still a dominica II classis for this purpose even though the Transfiguration, not the Sunday, is [observed] -- so Sixtus (Class3) has no standing for the slot at all, the same as on any other II-class Sunday (contrast [test_ii_class_sunday_admits_only_ii_class_commemoration] above, romanus, Class3, excluded the identical way on an ORDINARY II-class Sunday). - ORACLE, independently fetched (missalemeum's own /api/v5/calendar JSON, not the small-model webpage summary, which proved unreliable for this exact question): 2023-08-06 (a Sunday) -- title Transfiguration of Our Lord, commemorations empty, displaced Pope Sixtus II, Felicissimus and Agapitus, Martyrs -- Sixtus displaced, not commemorated. Control, 2026-08-06 (a Thursday, no Sunday collision) -- Sixtus present in commemorations. Being a Sunday is exactly what excludes him. Deliberately NOT a bare "comms=[]" pin (this project's own catalogued vacuity flavour: a count/emptiness assertion that would pass even if nothing had ever been offered): [omitted_has] first proves the Sunday really WAS a candidate that reached [disposition] and was actively excluded, not merely never constructed. *) let test_rg16a_lord_feast_no_sunday_commemoration_2028 () = let d = fetch 2028 8 6 in Alcotest.(check bool) "2028-08-06: the impeded Sunday is in [omitted], proving RG16(a) actively fired (not merely never offered)" true (omitted_has d "ef-time-after-pentecost-sunday-9"); Alcotest.(check string) "2028-08-06: the Transfiguration observed; NO commemoration at all -- RG16(a)'s own \"cum omnibus iuribus \ 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 name_la=- comms=[] in=- out=[]" (describe d) (* Holy Family (RG 17(b), scan-verified, docs/research/rules-register.md §4/§6.0): "festum S. Familiae Iesu, Mariae, Ioseph, celebrandum dominica prima post Epiphaniam" -- first Sunday after Epiphany, II class, EVERY year, taking the Sunday's own place "cum omnibus iuribus et privilegiis" (RG 17(b)'s own closing clause, the same formula RG 16(a) uses above). Three shapes, each independently verified against the primary text BEFORE being typed in here, per this file's own header rule: 1. AN ORDINARY YEAR (2026, 11 January): no fixed-date competitor in the 7-13 January window besides St Hyginus (11 Jan, Class3, Commemoration_only per data/ef/sanctoral.sexp) -- excluded from the day's single Sunday slot outright by RG 111(b)'s own rank floor ("de festo II classis"), the SAME mechanism test_precedence_ef.ml's own "II-class Sunday admits only a de-festo-II-classis commemoration" pin already proves for a different date -- so comms=[] is not itself new ground, only Holy Family's own slug/rank/colour/season are. `date -d 2026-01-11 +%A` = Sunday, independently confirmed. 2. THE 13-JANUARY COLLISION (2030, the latest possible date -- Epiphany itself a Sunday, 6 January): the fixed Commemoration of the Baptism of the Lord (13 Jan, Class2, subject Lord, data/ef/sanctoral.sexp) would otherwise contest the day directly, not merely lose a commemoration slot -- RG 91 entry 14's own "primum mobilia, deinde fixa" (precedence_ef.ml's own [entry_14_movable_band]) is what keeps Holy Family observed, and RG 112(a) -- directly confirmed by the Holy Family Mass propers' own more specific 13-January rubric, both photographic scans, word for word: "Si festum S. Familiae occurrerit die 13 ianuarii, Missa dicitur de festo S. Familiae, sine commemoratione Baptismatis D.N.I.C., et sine commemoratione dominicae" -- is what keeps comms=[] rather than admitting the Baptism as an ordinary Class2 commemoration. `date -d 2030-01-13 +%A` = Sunday, independently confirmed; 2030 is one of the seven years in the 2005-2050 window this collision occurs (register §6.0's own list, test_differential.ml's own C15). 3. THE EARLIEST POSSIBLE DATE (2024, 7 January -- Epiphany a Saturday): the OTHER end of RG 17(b)'s own 7-13 January range, proving the window's own boundary, not only its middle and its latest instance. No fixed-date competitor exists this early in the window either. `date -d 2024-01-07 +%A` = Sunday, independently confirmed. All three: season=christmastide (RG 72-73's own 1-13 January boundary, unaffected by Holy Family), week=- (Christmastide carries no numbered weeks at all, [T.week_origin]'s own [None] case -- unaffected by which Sunday of it this is), slug=ef-time-after-epiphany-sunday-1 (unchanged from the plain Sunday key this date always carried -- temporal_ef.ml's own comment on why RG 17(b) does not need a new lectionary key), rank =class-2, colour=white -- AND, fix round 1 (coordinator finding 4), subject=lord: the ONE field that actually distinguishes Holy Family from an ordinary, unnamed Sunday (every other field above was already identical before temporal_ef.ml's own fix -- [describe] originally omitted [subject], so two of these three pins would have stayed green even with the feature fully reverted; see [describe]'s own comment). *) let test_holy_family_ordinary_year_2026 () = check ~msg:"2026-01-11: Holy Family, ordinary year -- Hyginus (Class3, Commemoration_only) has no \ 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 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 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 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 quae occurrit a die 2 ad 5 ianuarii (secus die 2 ianuarii)" -- unlike Holy Family (RG 17(b), immediately above), this window CAN be, and routinely is, empty of a Sunday (3,619 of 8,417 years domain-wide) -- the calendarium's own fallback, "vel, ea deficiente, die 2 ianuarii", is what the SECOND pin below exercises. *** THIS FILE'S OWN VACUITY WARNING, APPLIED DIRECTLY *** [test_holy_name_sunday_shape_2026] pins a year where the Sunday shape fires -- slug/rank/colour/season/comms here are ALL already what [T.sunday_slug]'s Christmastide branch computed before this task's fix (the identical accident Holy Family's own [describe] note above already explains for its shape): an unnamed Sunday and Holy Name of Jesus share every one of those fields on this date. Reverting the fix leaves this pin GREEN except for [subject] -- the ONE field it actually tests, same discipline as Holy Family's own "coordinator finding 4" fix. This pin earns its place only by asserting [subject] explicitly, not by pinning the whole line uncritically. [test_holy_name_fallback_2029] is the pin that actually has teeth against the LARGER of the two defects this task closed: before the fix, colitur emitted NO Holy Name office at all in a fallback year -- not merely an unnamed generic Sunday (Holy Family's own pre-fix shape), but the ordinary Christmastide ferial slug (`ef-christmas-1-tuesday`, class-4) the task brief's own example names. Reverting the fallback half of the fix reddens this pin on EVERY field (slug, rank, subject), not only one -- the shape this file's header calls "the whole line moved", the opposite of the Sunday pin's own narrow, single-field teeth. *) let test_holy_name_sunday_shape_2026 () = check ~msg:"2026-01-04: Holy Name of Jesus, Sunday shape -- oracle-corroborated (missalemeum's own \ 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 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 \ calendarium's \"vel, ea deficiente, die 2 ianuarii\") -- no Sunday falls 2-5 January 2029 \ (`date -d 2029-01-0{2,3,4,5} +%u` = 2,3,4,5, independently confirmed), so 2 January itself \ carries the feast; before this task's fix colitur emitted `ef-christmas-1-tuesday class-4` \ 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 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 round -- F2 named 30 June's own total absence of golden coverage directly ("no golden pin on any 30 June date"), and F1 named the shape-(c) collision as a real day this suite otherwise never exercises end-to-end against real data (both new [admit_cases] rows are synthetic candidates, not `Calendar.day` over the real committed layer). *** BOTH PINS ARE BLIND TO COMMEMORATION ORDER -- STATED HONESTLY, NOT CLAIMED AS PROOF OF F1's OWN FIX *** [describe]'s own `comms` field (this file's header, above) sorts the commemoration list alphabetically before rendering (`List.sort compare`) -- deliberately, so a golden pin's own STRING comparison is not accidentally order-sensitive where nothing textual requires it to be. That means this file, like the differential and the oracle's own [identity_diff] (test_oracle.ml), CANNOT see whether [rg110_additions] emits `chair-of-st-peter, paul` or `paul, chair-of-st-peter` -- both sort to the same string. The ONLY place in this codebase's test suite that asserts commemoration ORDER at all is `test_precedence_ef.ml`'s own [admit_cases] table (`Alcotest.(check (list string))`, not a sorted string) -- see precedence_ef.ml's own [rg110_additions] comment for the citation this uses to fix the order, and CLAUDE.md's "know what each layer cannot see" section for this as a permanent, structural limit, not a gap this task's own pins happened not to close. These two pins prove PRESENCE and IDENTITY of both commemorations on a real, `Calendar.day`-resolved date -- genuine ground no other pin in this file currently covers -- not order. *) let test_rg110_june_30_2026 () = check ~msg:"2026-06-30: RG 110's 30-June direction -- In Commemoratione Sancti Pauli Apostoli observed, \ +commemoration-of-st-peter (data/ef/adjustments.sexp's own `Add` directive) the sole \ 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 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 \ (Septuagesima, not I-class) II-class Sunday and is admitted only as a commemoration under \ RG 111(b)'s own rank floor; Paul rides along too, uncapped (`date -d 2004-02-22 +%A` = \ 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 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 finding, item 1, reverted; see register §6.0 for the full account). The Purification (2 Feb, calendarium "IN PURIFICATIONE B. MARIAE VIRG.") stays [subject = Lord] -- the user has ruled: follow the oracle. missalemeum treats it exactly as RG 16(a)'s own "festum Domini" case (independently fetched, `/api/v5/calendar` JSON): 2020-02-02 (a Sunday) -- `{"title":"Purification of the Blessed Virgin Mary","tags":["IV Sunday after Epiphany"],...,"commemorations":[],"displaced":[]}` -- the Sunday named only as a TAG (the underlying temporal placement), not commemorated at all; matches 2014-02-02 exactly. Contrast, the SAME oracle on an ordinary Marian feast (2019-09-08, the Nativity of the BVM): `{"title":"XIII Sunday after Pentecost",...,"commemorations": [{"title":"Nativity of the Blessed Virgin Mary",...}],...}` -- the Sunday observed, the feast merely commemorated, the OPPOSITE pattern -- proving missalemeum does not treat every Marian feast this way, only the Purification specifically. `date -d 2025-02-02 +%A` = Sunday, independently confirmed. Unlike 2028-08-06, no second sanctoral candidate exists on 2 February (data/ef/sanctoral.sexp has exactly one 2 February entry) -- a genuinely clean "comms=[]" case, complementing the pair above rather than duplicating it. *) let test_purification_on_a_sunday_2025 () = check ~msg: "2025-02-02: the Purification observed (subject Lord, unretagged -- the oracle's own treatment); NO \ 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 name_la=- comms=[] in=- out=[]" (* ------------------------------------------------------------------ *) (* RG 91 entry 24 ("Festa III classis, in calendario Ecclesiae universae inscripta") outranks entry 28 ("feriae IV classis") -- ef-rebootstrap (2026-08-12). Fifteen data/ef/sanctoral.sexp entries, 6 March-5 April, were wrongly bootstrapped `rank = commemoration` (Commemoration_only, which RG 91's table has no row for at all, register §6.1's own Maurice/ Thomas finding) where the 1962 calendarium gives each a real class number instead; corrected upstream in lectio's own generator and re-bootstrapped here (source SHA-256 1b303ef2...). Only 7 of the 15 ever land on a date that collides with a plain CLASS-4 feria somewhere in the domain -- fact-checked by a full 1583-9999 blast-radius sweep finding zero diff rows for the other 8 anywhere in the domain, not assumed. CORRECTED (ef-rebootstrap fix round 1, F1): this comment previously gave a single reason for the other 8's silence -- "always fall inside Lent/ Passiontide proper, RG 91 entry 22, which already outranks entry 24" -- WRONG for 3 of the 8, measured directly against the domain-wide season breakdown per slug: `gabriel-the-archangel` (24 Mar) lands in PASCHALTIDE 226 times, `john-damascene` (27 Mar) 846 times, `john-of-capistrano` (28 Mar) 1108 times -- always at `class-1` there (inside the Easter Octave, RG 91 entry 2/10), never a class-4 feria. Entry 22 itself is also narrower than "Lent/Passiontide" suggests (its own text excludes the Ember days). The TRUE, general shield, checked against every (season, rank) pair these 8 slugs' dates ever land in domain-wide: whichever office already occupies the date is EITHER class-1 or class-2 (an Easter-Octave/Holy-Week/I-class-Sunday day, entries 2/6/7/10; a II-class Sunday or Ember feria, entries 15/18) -- which trivially outranks ANY class-3 candidate regardless of status, and also excludes it from commemoration by RG 111(a)/(b)'s own rank floors the same way regardless of status -- OR the ordinary Lent/Passiontide class-3 feria itself, entry 22, which outranks entry 24 for OBSERVATION but (RG 111(c)/(d), no ferial-class gate on an "ordinary" sanctoral candidate) admits the losing saint's commemoration identically whether `Commemoration_only` or a genuine `Feast` -- so no context these 8 dates ever reach anywhere in the domain distinguishes the two statuses in either direction, observation or commemoration. Not "always Lent" -- "always something at entry ≤22 already occupies the day". These are the SIX dates the task brief that started this re-bootstrap named as producing "a wrong observed office" under the OLD data (2008-04-02/04/05, 2038-03-06/08/09) -- [test_easter_extreme_2038_late_modern]'s own header above is the record of why they were deliberately left unpinned until now. *) let test_iii_class_feast_wins_class4_feria () = (* Two [omitted_has] checks, one per season family (Paschaltide, Septuagesima), prove the displaced CLASS-4 feria actually reached [disposition] and was actively omitted under RG26 ("IV-class ferias are never commemorated"), not merely absent because no candidate was ever offered -- this file's own established convention (the RG16(a) and "IV-class ferias never commemorated" tests above), not repeated for all six to avoid duplicating the same proof six times. *) let d1 = fetch 2008 4 2 in Alcotest.(check bool) "2008-04-02: the displaced class-4 Paschaltide feria is in [omitted] (RG26), proving RG91 entry24>28 fired" 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 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 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 name_la=- comms=[] in=- \ out=[]"; let d4 = fetch 2038 3 6 in (* ef-bvm-saturday task: 6 March 2038 is a SATURDAY, so the displaced temporal candidate is now RG 78's own BVM Saturday office ({!Rite_ef.Temporal_ef}'s own [bvm_saturday_names] citation) rather than a bare ferial -- but per that citation's own "Slug" paragraph the SLUG is deliberately left unchanged (reused, not replaced), precisely so this test's own [omitted_has] probe still needs no update: the displaced candidate is still named "ef-septuagesima-2-saturday", only its colour/subject/name would have differed had it won. RG 91 entry 24 (Sts Perpetua and Felicity) still outranks it either way -- entry 24 < entry 27, both above entry 28 -- so the disposition/win outcome this test proves is genuinely unchanged by this task, now more precisely entry 24 > entry 27 rather than > 28 for this one date (a Saturday), not that the test itself needed touching. *) Alcotest.(check bool) "2038-03-06: the displaced class-4 feria (RG78's own BVM-Saturday office, \ for this Saturday) is in [omitted] (RG26), proving RG91 entry24>27 fired" true (omitted_has d4 "ef-septuagesima-2-saturday"); 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 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 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 name_la=- comms=[] in=- \ out=[]" (* ------------------------------------------------------------------ *) (* RG 91 entry 27 / RG 78-79 (Caput IX, "De sancta Maria in sabbato") -- ef-bvm-saturday task, Rite_ef.Temporal_ef's own [bvm_saturday_names] citation has the full primary-source argument. Two real-data pins, the task brief's own worked example and its mirror-image negative case, matching this file's own header rule: EVERY literal below was checked by hand against `colitur day 2026` before being typed in here (this task's own report has the full session log), never copied from a run and rationalised after. *) (* The task brief's own worked example, checked against the oracle (missalemeum) directly: "2026-08-01|4|w|V Mass of the B. V. M. -- Salve, Sancta Parens|Saturday_after_IX_Sunday_after_Pentecost|Holy Machabees". colitur's own rank (4) and colour (white) now match; the oracle's own numbered-Mass title (RG 309(a)'s own "iuxta temporum diversitatem", not modelled here -- {!bvm_saturday_names}'s own "Slug" paragraph) and the observed day's own English identity remain outside what this comparator can see (M18's own limit) -- this pin instead proves what colitur DOES compute: white/class-4/subject Bvm/the Latin title, and Holy Machabees (real data/ef/sanctoral.sexp entry, Commemoration_only, Class3, 1 August) still admitted as an ORDINARY commemoration alongside it, matching the oracle's own commemoration list exactly. *) let test_bvm_saturday_2026 () = check ~msg:"2026-08-01: the BVM Saturday office observed, white overriding Time after Pentecost's green, \ Holy Machabees commemorated -- matches the task brief's own oracle example" 2026 8 1 "2026-08-01 saturday season=time-after-pentecost week=9 slug=ef-time-after-pentecost-9-saturday \ rank=class-4 colour=white subject=bvm name_la=Officium sanctae Mariae in sabbato \ comms=[holy-machabees:ordinary] in=- out=[]" (* The mirror-image case: RG 78's own protasis is FALSE here (a real feast wins the Saturday outright), so the BVM-Saturday-shaped temporal candidate must lose and be omitted under RG 26, exactly like the plain ferial candidate it replaces always was -- no commemoration at all, proving [band]/[disposition] need no special case for this office (the design claim the task report makes explicitly). ALSO the one live data witness where the winning candidate itself carries [subject = Bvm] (data/ef/adjustments.sexp's own `Edit most-holy-name-of-mary ((Set_subject Bvm))`) -- proving no Bvm-vs-Bvm confusion with a RG112(a)-style subject rule: [omitted_has] below confirms the loser is genuinely reported omitted (RG26 fires on [rank = Class4] alone, checked ahead of any subject-based branch in {!Rite_ef.Precedence_ef.disposition}), not silently swallowed by a same-subject exclusion that does not exist for [Bvm] anywhere in this codebase. *) let test_bvm_saturday_loses_to_most_holy_name_of_mary_2026 () = let d = fetch 2026 9 12 in Alcotest.(check bool) "2026-09-12: the displaced BVM-Saturday-shaped candidate is in [omitted] (RG26), not silently absent" true (omitted_has d "ef-time-after-pentecost-15-saturday"); Alcotest.(check string) "2026-09-12: Most Holy Name of Mary (III class, subject Bvm, data/ef/adjustments.sexp) outranks the \ class-4 BVM-Saturday candidate; no commemoration at all" "2026-09-12 saturday season=time-after-pentecost week=15 slug=most-holy-name-of-mary rank=class-3 \ colour=white subject=bvm name_la=- comms=[] in=- out=[]" (describe d) (* RG112(d), fix round 1 (coordinator finding F1): PE.marian_slugs's own citation (precedence_ef.ml) has the full RG112(d) argument, including the 16 July "Missa dici potest aut ... aut ..." rubric found on both photographic scans. 16 July 2033 is a real otherwise-unoccupied Saturday; before this fix, [comms] here read "[our-lady-of-mt-carmel:ordinary]" (confirmed against real pre-fix `colitur day 2033` output). *) let test_bvm_saturday_excludes_mt_carmel_2033 () = let d = fetch 2033 7 16 in Alcotest.(check bool) "2033-07-16: Mt Carmel is in [omitted] (RG112(d)), not silently dropped from the record" true (omitted_has d "our-lady-of-mt-carmel"); Alcotest.(check string) "2033-07-16: the BVM Saturday office observed, white; NO commemoration of Mt Carmel (RG112(d))" "2033-07-16 saturday season=time-after-pentecost week=5 slug=ef-time-after-pentecost-5-saturday \ rank=class-4 colour=white subject=bvm name_la=Officium sanctae Mariae in sabbato comms=[] in=- out=[]" (describe d) (* ------------------------------------------------------------------ *) (* RG 80/81/109(f), the Major Litanies (ef-major-litanies task). Every date below independently derived from the primary text, not read off a `colitur day` run first and rationalised (this file's own header, rule 3): Easter's own date for each civil year comes from Computus (already independently Gauss-cross-checked by this file's own extreme-year pins), 25 April's Easter-offset and weekday follow arithmetically from that, and the RULE applied at each offset (RG 80's transfer condition; RG 91 entries 15/16 for the Sunday-vs-Mark band comparison; RG 111(b)'s privilege-overrides-ordinary clause) is quoted at Rite_ef.Precedence_ef's own [disposition]/[admit]/[transfer_target] and at data/ef/expected-divergences-missalemeum.sexp's own M5/M20 entries, which independently adjudicate the one substantive rubric question here (WHO wins the Sunday's single slot) against the missalemeum oracle. *) (* ------------------------------------------------------------------ *) (* The ORDINARY case (~97.7% of years, register's own measurement): 25 April 2026 is a Saturday (independently checked via `date -d 2026-04-25 +%A`, this file's own header rule 2), Easter+20 (Easter 2026 = 5 April, itself independently checked the same way against a published 2026 Easter date). St Mark (II class, RG 91 entry 16) wins the day outright over the ordinary Class4 Paschaltide feria (entry 28); the Litanies, Commemoration_only, is the day's ONLY other candidate and is admitted uncontested ({!Rite_ef.Precedence_ef.admit}'s [Class2, false] case: one slot, table order alone, no rival). This is the SAME date and shape data/ef/expected-divergences-missalemeum.sexp's own [M5] entry adjudicates against the real missalemeum oracle (verdict colitur, a naming-convention difference only -- "The Major Litanies" vs missalemeum's own "Pro rogationibus"). *) let test_major_litanies_ordinary_2026 () = check ~msg:"2026-04-25: St Mark observed outright (RG91 e16 > e28); the Major Litanies (RG80/109(f)) ride \ along uncontested" 2026 4 25 "2026-04-25 saturday season=paschaltide week=3 slug=mark rank=class-2 colour=red subject=saint name_la=- \ comms=[major-litanies:privileged] in=- out=[]" (* The FOUR Sunday-displacement years in 2005-2050 (this task's own measurement, register): 25 April is a Sunday, so St Mark (entry 16, II class) loses to it exactly as any other II-class feast would (entry 15 < entry 16), becoming an ordinary commemoration CANDIDATE rather than the observed day -- and then loses the day's own single slot to the Litanies (RG 111(b): "quæ tamen omittitur si commemoratio privilegiata facienda sit" -- the ordinary de-festo-II-classis commemoration is DROPPED once a privileged one is due). [omitted_has] on each date below confirms Mark is genuinely reported dropped, not silently absent -- "omitted: admission limit reached", {!Precedence.resolve}'s own generic reason for a candidate [disposition] admitted to the contest but [admit] then cut. Two different generic Sunday slugs appear (week 4 in 2010/2021, week 5 in 2027/2032) because Easter falls on a different date in each pair -- neither is hand-picked, both are what [Temporal_ef.sunday_slug] actually computes. *) let test_major_litanies_displaces_mark_on_ii_class_sunday () = List.iter (fun (y, week) -> let d = fetch y 4 25 in Alcotest.(check bool) (Printf.sprintf "%d-04-25: St Mark is in [omitted] (RG111(b)'s privileged-commemoration override), not \ silently dropped" y) true (omitted_has d "mark"); Alcotest.(check string) (Printf.sprintf "%d-04-25: the Sunday observed (II class); ONLY the Litanies commemorated, Mark \ displaced (RG111(b))" y) (Printf.sprintf "%d-04-25 sunday season=paschaltide week=%d slug=ef-easter-sunday-%d rank=class-2 colour=white \ subject=temporal name_la=- comms=[major-litanies:privileged] in=- out=[]" y week week) (describe d)) [ (2010, 4); (2021, 4); (2027, 5); (2032, 5) ] (* The OTHER RG 80 trigger shape, complementing 1666/2038 above (Easter Sunday itself = 25 April): here Easter MONDAY = 25 April (Easter = 24 April 2011, independently Gauss-derivable and already the domain's own register-cited "Easter Monday" marker, [ef-easter-1-monday]). RG 80's "following Tuesday" is one day later this time (26 April, not 27) -- both shapes converge on the SAME offset, Easter+2, never on a fixed civil-date difference. *) let test_major_litanies_transfer_2011_easter_monday () = check ~msg:"2011-04-25 Easter Monday (RG80's SECOND trigger): Litanies depart for the following Tuesday, \ 26 April" 2011 4 25 "2011-04-25 monday season=paschaltide week=1 slug=ef-easter-1-monday rank=class-1 colour=white \ subject=temporal name_la=- comms=[] in=- out=[major-litanies->2011-04-26]"; check ~msg:"2011-04-26 Easter+2: the Litanies land here, commemorated and privileged, exactly one day after \ origin (not two, unlike the Easter-Sunday shape)" 2011 4 26 "2011-04-26 tuesday season=paschaltide week=1 slug=ef-easter-1-tuesday rank=class-1 colour=white \ subject=temporal name_la=- comms=[major-litanies:privileged] in=- out=[]" (* ---- Task 10: one pin per step of the reading-resolution chain ---- The chain has four steps, and a citation regression is far easier to diagnose when the failing pin names WHICH step broke. Every literal below was read out of the photographic scans first (line numbers given per pin), then compared with colitur -- not the other way round. Step 4 deserves special note: it is the ONE step with no external oracle witness of any kind (register §6.7 -- the five Common-routed saints are the observed office on just five days in all of 2005-2050, and not one falls inside layer 4's own 2026-2027 fixture window; layer 3 sees those days but lectio resolves the literal "-"/"-" sentinel there, which is what C18 is gated on, so it confirms only that colitur emits SOMETHING). These two pins are therefore the first independent confirmation that route has ever had, which is also why step 4 gets two of the six rather than one. *) (* STEP 1 -- a sanctoral proper: the citation lives on the Celebration itself, no walk, no Common. 8 March 1938^H2038, "S. Ioannis a Deo Conf., III classis": "Lectio libri Sapientiae. Eccli. 31, 8-11" / "Sequentia sancti Evangelii secundum Matthaeum. Mt. 22, 34-46" (scan1.txt:27732-27734 + 27769-27770; scan2.txt:30698-30699 + 30733-30736; page image p. 485). The Missal prints him a FULL Mass with its own assigned Gospel -- the Epistle happens to coincide with the Common of a Confessor not a Bishop's, but the Gospel does not (that Common has Luke 12:35-40), which is what makes this a proper and not a Common, and so a step-1 case rather than a step-4 one. NOTE the plan named 2030-01-13 for this step; that date is a TEMPORAL day (Holy Family, carried on the generic Sunday slug per RG 17(b)) and would not have exercised step 1 at all. *) let test_readings_step1_sanctoral_proper () = check_readings ~msg:"step 1: sanctoral proper (John of God, 8 March)" 2038 3 8 "2038-03-08 slug=john-of-god first=Ecclus 31:8-11 gospel=Matt 22:34-46" (* STEP 2 -- a temporal day with its own direct lectionary entry. 23 February 2026 is "Feria II post dominicam I in Quadragesima" (heading, scan1.txt: 8137): "Lectio Ezechielis Prophetae. Ezech. 34, 11-16" (scan1.txt:8138- 8139) / "Sequentia sancti Evangelii secundum Matthaeum. Mt. 25,31-46" (scan1.txt:8199). A Lenten feria is the right shape here because Lent's ferias each have their OWN Mass -- they never walk back, so a regression in step 3 cannot mask a regression in step 2 on this date. The book abbreviation is "Ezech", not "Ezek": this pin was first written from the scan as "Ezek 34:11-16" and failed, and the difference turned out to be notation alone -- colitur's own spelling is in fact the Missal's own ("Ezech. 34, 11-16", above). Recorded rather than quietly amended, since a failing pin whose only fault is an abbreviation is exactly the kind of thing a later reader will otherwise re-litigate. Cross-engine abbreviation differences are normalised away in layer 3 (test_differential.ml's own A/B normalisation) and so are invisible there; this layer sees them. *) let test_readings_step2_temporal_proper () = check_readings ~msg:"step 2: temporal proper (Lent I Monday)" 2026 2 23 "2026-02-23 slug=ef-lent-1-monday first=Ezech 34:11-16 gospel=Matt 25:31-46" (* STEP 3 -- the ferial resumption: a day with NO Mass of its own, which therefore repeats its preceding Sunday's. 1 December 2025 is the Monday after Advent I, and Advent's ferias (unlike Lent's) have no proper Mass, so the citation must be Advent I Sunday's own: "ad Romanos. Rom. 13, 11-14" (scan1.txt:4878) / "dum Lucam. Luc. 21, 25-33" (scan1.txt:4912). That the pinned value equals the SUNDAY's, not the Monday's own, is the whole point of the pin. *) let test_readings_step3_ferial_resumption () = check_readings ~msg:"step 3: ferial resumption (Advent I Monday reads Advent I Sunday)" 2025 12 1 "2025-12-01 slug=ef-advent-1-monday first=Rom 13:11-14 gospel=Luke 21:25-33" (* STEP 4 (a) -- the Common route. 6 March 2038, "Ss. Perpetuae et Felicitatis Martyrum, III classis", whose own entry directs: "Missa Me exspectaverunt, de Communi non Virginum I loco [35]" (scan1.txt:27634- 27635). That Common -- COMMUNE NON VIRGINUM, "Pro Martyre non Virgine" (scan1.txt:42560 ff) -- reads "Lectio libri Sapientiae. Eccli. 51, 1-8 et 12" (scan1.txt:42589-42590) and "Sequentia sancti Evangelii secundum Matthaeum. Mt. 13, 44-52" (scan1.txt:42606). 2038 is the only year in 2005-2050 in which she is the OBSERVED office at all. *) let test_readings_step4_common_felicitas () = check_readings ~msg:"step 4: Common of Non-Virgins I (Perpetua & Felicitas)" 2038 3 6 "2038-03-06 slug=sts-felicitas-perpetua first=Ecclus 51:1-8, 12 gospel=Matt 13:44-52" (* STEP 4 (b) -- the SECOND Common, deliberately a different one, so the pin pair distinguishes "the Common route works" from "one Common's data is right". 9 March 2038, "S. Franciscae Romanae Vid., III classis", directed to "Missa Cognovi, de Communi non Virginum" -- the second Mass of that same Common, which reads "Lectio libri Sapientiae. Prov. 31, 10-31" (scan1.txt:42679) and shares the Gospel "Mt. 13, 44-52" (scan1.txt:42720). The shared Gospel with (a) is the Missal's own doing, not a colitur collapse -- which is exactly why both Epistles are pinned too. *) let test_readings_step4_common_frances () = check_readings ~msg:"step 4: Common of Non-Virgins II (Frances of Rome)" 2038 3 9 "2038-03-09 slug=frances-rome first=Prov 31:10-31 gospel=Matt 13:44-52" (* THE DISPLACED-SUNDAY FERIA -- the case that separates the temporal slug from the observed one, and the one the plan singles out. It is pinned here as KNOWN-DIVERGENT OUTPUT, deliberately and with the divergence named, NOT blessed as correct: this is test_oracle.ml's own M26 shape 2(b) (verdict open). 26 October 2026 is a feria of the week whose Sunday was displaced by Christ the King (I class, movable, "Dominica ultima octobris"). The general mechanism -- a week's ferias follow their OWN Sunday's temporal identity even when that Sunday is impeded -- is the shape RG 69 establishes for the Nativity Octave, so the displaced ordinary Sunday's Mass is what the ferias should read; colitur's step 3 instead walks back to the DISPLACING feast and emits Christ the King's own Gospel (John 18:33-37, "Art thou a king?"), which is the literal in this pin. No Missal-propers rubric specific to Christ the King's own week was found (checked: scan1.txt:39140-39163, no rubric precedes that Mass heading, unlike Holy Name's and Holy Family's own), so M26 stays verdict open rather than being asserted against a citation that does not exist. WHEN M26 IS FIXED THIS PIN MUST FAIL -- that is its purpose. Update it deliberately then; do not regenerate it. Two things this pin established that M26's own note did not record. First, BOTH parts come from the displacing feast, not only the Gospel M26 cites: the Epistle here is Col 1:12-20, which is Christ the King's own, so step 3 is transplanting the whole Mass rather than half of it. Second, the reference carries a TRAILING PERIOD ("Col 1:12-20."), a blemish inherited through the bootstrap from the source data. It is pinned verbatim rather than tidied, because this pin's job is to state what colitur actually emits today; the period is noted here as a separate, cosmetic data defect and is deliberately not fixed under a task about test coverage. Layer 3 cannot see it (its A/B normalisation strips punctuation before comparing), which is why it surfaced here first. *) let test_readings_displaced_sunday_feria_known_divergent () = check_readings ~msg:"displaced-Sunday feria: pins M26 shape 2(b)'s KNOWN-WRONG walkback, not correct output" 2026 10 26 "2026-10-26 slug=ef-time-after-pentecost-22-monday first=Col 1:12-20. gospel=John 18:33-37" (* ---- Rogation Wednesday (RG 87/88/89), movable-date-specs task ---- RG 87, verbatim (scan1.txt:691): "Litaniae minores seu Rogationes, per se, assignantur feriis II, III et IV ante festum Ascensionis Domini" -- Monday, Tuesday AND Wednesday. colitur built the first two as temporal offices from the start; the Wednesday had no channel at all until Date_spec grew [Easter_offset], because Easter+38 IS the Ascension Vigil by construction and there is no (month, day) a Fixed spec could anchor to. RG 88 keeps it out of the Office entirely, so the Vigil remains the observed day and this is only ever a commemoration. RG 89 routes it through the Major Litanies' rules -- but RG 109's closed list of privileged commemorations names only "de Litaniis MAIORIBUS", never minoribus, so by RG 107's closing rule it is ORDINARY. That asymmetry is the whole point of pinning two years rather than one: 2024 -- nothing else competes, so the single commemoration RG 111 allows on a II-class day is the Rogation itself. 2026 -- St Robert Bellarmine (III class) is impeded onto the same day and takes that one slot instead: RG 113 orders admissions by RG 91's table, and a Commemoration_only candidate has no row in it at all (band returns [unclassified]), so a genuine feast outranks it. Both weekdays independently checked with `date -d`. *) let test_rogation_wednesday_admitted_2024 () = check ~msg:"2024: Rogation Wednesday is the one admitted commemoration" 2024 5 8 "2024-05-08 wednesday season=paschaltide week=6 slug=ef-ascension-vigil rank=class-2 colour=white subject=temporal name_la=- comms=[rogation-wednesday:ordinary] in=- out=[]" let test_rogation_wednesday_yields_to_a_feast_2026 () = check ~msg:"2026: an impeded III-class feast takes the single slot instead" 2026 5 13 "2026-05-13 wednesday season=paschaltide week=6 slug=ef-ascension-vigil rank=class-2 colour=white \ subject=temporal name_la=- comms=[robert-bellarmine:ordinary] in=- out=[]" (* RG 128, transcribed in docs/research/rules-register.md §3b: violet is used for "II/III-class vigils outside Paschaltide". Two of colitur's five vigils disagreed with that rule until the ef-oconnell-rubrics branch -- the Assumption's (II class, 14 August) was White and St Lawrence's (III class, 9 August) was Red. Both are outside Paschaltide, so both are violet. O'Connell, The Celebration of Mass 4th ed. (1964), section 4(c) states the same rule and its footnote 169 names the sole exception -- "the only vigil of II class within Eastertide is that of the Ascension and its colour is white" -- which colitur already emits correctly (ef-ascension-vigil, white, pinned by the two Rogation Wednesday cases just above). Pinned in years where each vigil is actually OBSERVED rather than impeded. 14 August 2025 is a Thursday and the Assumption always keeps 15 August (I class, nothing in the universal calendar outranks it), so that pin is stable in any year the vigil's own day is free. ST LAWRENCE'S PIN MOVED 2025 -> 2027 when RG 33's third omission trigger was implemented. Its original comment reasoned only about the vigil's OWN weekday -- "9 August 2025 is a Saturday", true, so RG 33's Sunday trigger does not fire -- and missed that the rule also looks at the FEAST: 10 August 2025 is a Sunday, the II-class Sunday reduces St Lawrence to a commemoration, and "vel si festum cui praemittitur... ad commemorationem reduci contingat" omits the vigil entirely. The day now keeps the BVM Saturday Office instead, pinned separately just below. 9 August 2027 is a Monday and 10 August 2027 a Tuesday (both `date -d`-checked), so St Lawrence keeps his own day there and the vigil genuinely is observed -- which is what this pin has always been trying to assert about RG 128's colour rule. *) let test_vigil_of_st_lawrence_is_violet_2027 () = check ~msg:"RG 128: III-class vigil outside Paschaltide is violet, not red" 2027 8 9 "2027-08-09 monday season=time-after-pentecost week=12 slug=vigil-of-st-lawrence \ rank=class-3 colour=violet subject=saint name_la=- comms=[romanus:ordinary] in=- out=[]" (* RG 33's THIRD omission trigger -- "vel si festum cui praemittitur in alium diem transferri aut ad commemorationem reduci contingat" -- on the shipped universal calendar, no overlay involved. 10 August 2025 is a Sunday; the II-class Sunday outranks St Lawrence's II-class feast (RG 15), so the feast is "ad commemorationem reducta" on its own day and the vigil of 9 August is "penitus omissa". This is the clause's most common live shape by a wide margin: 1 199 of the 1 744 days it fires on across 1583-9999 are St Lawrence's vigil dropped because 10 August fell on a Sunday. The day does not become a bare feria -- 9 August 2025 is a Saturday, so RG 78's votive Office of the BVM takes the freed IV-class Saturday, which is why this pin reads white and subject=bvm. St Romanus keeps his commemoration either way (RG 111). INDEPENDENTLY WITNESSED at the day level, though not by the Ordo this project already had. That one (extraordinaryform.org) omits the vigil here AND on 2027-08-09 where the clause says to keep it, so it never shows St Laurence's vigil at all and corroborates nothing -- a claim an earlier version of this comment got wrong in both directions before checking. The Latin Mass Society Ordo 2024-2025 for England and Wales does the job: 9 August 2025 is "OUR LADY on SATURDAY IV Cl W / Commem of St Romanus M", no vigil, and 10 August is the II-class Sunday with St Laurence reduced to a commemoration -- this pin's exact content. It is discriminating because that edition lists six other vigils as the day's office, including the Assumption's on 14 August 2025. See C39's own note in data/ef/expected-divergences.sexp. *) let test_rg33_vigil_omitted_when_its_feast_is_commemorated_2025 () = check ~msg:"RG 33: 10 Aug 2025 is a Sunday, so St Lawrence is only commemorated and his vigil is \ omitted entirely -- the BVM Saturday Office (RG 78) takes the freed day" 2025 8 9 "2025-08-09 saturday season=time-after-pentecost week=8 \ slug=ef-time-after-pentecost-8-saturday rank=class-4 colour=white subject=bvm \ name_la=Officium sanctae Mariae in sabbato comms=[romanus:ordinary] in=- out=[]" (* The same clause's OTHER half, "in alium diem transferri". 24 June 2038 is impeded by the Sacred Heart (I class, movable), so the Nativity of St John the Baptist is TRANSFERRED under RG 96 and its vigil of 23 June is omitted. 478 days across the domain take this shape (a further 67 via Corpus Christi). Pinned in 2038 because that year already carries an oracle fixture, so the divergence this creates is visible to layer 4 as well. *) let test_rg33_vigil_omitted_when_its_feast_transfers_2038 () = check ~msg:"RG 33: the Sacred Heart takes 24 June 2038, St John the Baptist transfers, \ and his vigil of 23 June is omitted entirely" 2038 6 23 "2038-06-23 wednesday season=time-after-pentecost week=1 \ slug=ef-time-after-pentecost-1-wednesday rank=class-4 colour=green subject=temporal \ name_la=- comms=[] in=- out=[]" let test_vigil_of_the_assumption_is_violet_2025 () = check ~msg:"RG 128: II-class vigil outside Paschaltide is violet, not white" 2025 8 14 "2025-08-14 thursday season=time-after-pentecost week=9 slug=vigil-of-the-assumption \ rank=class-2 colour=violet subject=saint name_la=- comms=[eusebius-confessor:ordinary] in=- out=[]" let suite = ( "golden pins (known-tricky years)", [ Alcotest.test_case "RG128: St Lawrence's vigil is violet (2027)" `Quick test_vigil_of_st_lawrence_is_violet_2027; Alcotest.test_case "RG33 third trigger: the vigil is omitted when its feast is reduced to a commemoration \ (2025-08-09, St Lawrence)" `Quick test_rg33_vigil_omitted_when_its_feast_is_commemorated_2025; Alcotest.test_case "RG33 third trigger: the vigil is omitted when its feast is transferred away \ (2038-06-23, St John the Baptist)" `Quick test_rg33_vigil_omitted_when_its_feast_transfers_2038; Alcotest.test_case "RG128: the Assumption's vigil is violet (2025)" `Quick test_vigil_of_the_assumption_is_violet_2025; Alcotest.test_case "Easter extreme: 1598 earliest (22 Mar, Gauss-verified)" `Quick test_easter_extreme_1598; Alcotest.test_case "Easter extreme: 1666 latest (25 Apr, Gauss-verified)" `Quick test_easter_extreme_1666; Alcotest.test_case "Easter extreme: 2038 late-modern instance of the latest date" `Quick test_easter_extreme_2038_late_modern; Alcotest.test_case "Annunciation transfer: 25 March falls inside Holy Week (2016)" `Quick test_annunciation_transfer_inside_holy_week_2016; Alcotest.test_case "Annunciation/Joseph double transfer (2008)" `Quick test_annunciation_joseph_double_transfer_2008; Alcotest.test_case "Annunciation RG96 exception NOT triggered: general walk suffices (2057, 2007, 2012)" `Quick test_annunciation_exception_not_triggered_general_walk_suffices; Alcotest.test_case "Annunciation RG96 exception triggered: walk would cross Easter (2024; see also 2016)" `Quick test_annunciation_exception_triggered_when_walk_would_cross_easter; Alcotest.test_case "2011-07-04: the Precious Blood transfer" `Quick test_precious_blood_transfer_2011; Alcotest.test_case "All Souls falling on a Sunday (2025)" `Quick test_all_souls_on_a_sunday_2025; Alcotest.test_case "Christmas falling on a Sunday (2022)" `Quick test_christmas_on_a_sunday_2022; Alcotest.test_case "Holy Thursday is white amid violet Passiontide (2026)" `Quick test_holy_thursday_is_white_2026; Alcotest.test_case "Advent/Lent Ember ferias commemorated when impeded (1900, 1902)" `Quick test_ember_ferias_commemorated_when_impeded; Alcotest.test_case "IV-class ferias never commemorated (2026)" `Quick test_iv_class_ferias_never_commemorated; Alcotest.test_case "RG111(b): a II-class Sunday admits only a de-festo-II-classis commemoration (2009, 2026)" `Quick test_ii_class_sunday_admits_only_ii_class_commemoration; Alcotest.test_case "RG16(a): a Feast of the Lord leaves the impeded Sunday with NO commemoration at all, not even an \ unrelated saint's own (2028-08-06, rubric + oracle)" `Quick test_rg16a_lord_feast_no_sunday_commemoration_2028; Alcotest.test_case "RG16(a), the Purification (oracle-ruled): observed outright, the Sunday not commemorated (2025-02-02)" `Quick test_purification_on_a_sunday_2025; Alcotest.test_case "Holy Family (RG17(b)), ordinary year (2026-01-11)" `Quick test_holy_family_ordinary_year_2026; Alcotest.test_case "Holy Family excludes the Baptism entirely on the latest possible date (RG91 e14 + RG112(a), 2030-01-13)" `Quick test_holy_family_excludes_baptism_2030; Alcotest.test_case "Holy Family, earliest possible date (2024-01-07)" `Quick test_holy_family_earliest_possible_date_2024; Alcotest.test_case "Holy Name of Jesus (RG17(a)), Sunday shape, subject asserted (2026-01-04)" `Quick test_holy_name_sunday_shape_2026; Alcotest.test_case "Holy Name of Jesus, fallback shape (RG17(a) \"secus die 2 ianuarii\", 2029-01-02 -- no Sunday in \ the window)" `Quick test_holy_name_fallback_2029; Alcotest.test_case "RG110: 30 June, In Commemoratione S. Pauli Apostoli + commemoration-of-st-peter (2026-06-30)" `Quick test_rg110_june_30_2026; Alcotest.test_case "RG110 shape (c): Chair of St Peter admitted only as a commemoration of an ordinary Sunday, Paul \ rides along (2004-02-22)" `Quick test_rg110_shape_c_2004; Alcotest.test_case "ef-rebootstrap: RG91 entry24 (III-class feast) outranks entry28 (class-4 feria) -- the six dates \ deferred since 2038's own Easter-extreme pin (2008-04-02/04/05, 2038-03-06/08/09)" `Quick test_iii_class_feast_wins_class4_feria; Alcotest.test_case "RG91 e27/RG78: the BVM Saturday office wins, Holy Machabees commemorated -- matches the task \ brief's own oracle example (2026-08-01)" `Quick test_bvm_saturday_2026; Alcotest.test_case "RG91 e27/RG78/RG26: the BVM Saturday office loses to Most Holy Name of Mary (subject Bvm too) \ and is omitted, no confusion (2026-09-12)" `Quick test_bvm_saturday_loses_to_most_holy_name_of_mary_2026; Alcotest.test_case "RG112(d), fix round 1 (F1): the BVM Saturday office excludes Mt Carmel's own commemoration \ (2033-07-16)" `Quick test_bvm_saturday_excludes_mt_carmel_2033; Alcotest.test_case "RG80/109(f): the Major Litanies, ordinary year, St Mark wins outright (2026-04-25)" `Quick test_major_litanies_ordinary_2026; Alcotest.test_case "RG111(b): the Major Litanies displace St Mark's own commemoration on a II-class Sunday (2010, 2021, \ 2027, 2032)" `Quick test_major_litanies_displaces_mark_on_ii_class_sunday; Alcotest.test_case "RG80's second trigger: Easter Monday = 25 April, the Litanies transfer to Easter+2 (2011)" `Quick test_major_litanies_transfer_2011_easter_monday; Alcotest.test_case "readings step 1: sanctoral proper (John of God, 2038-03-08)" `Quick test_readings_step1_sanctoral_proper; Alcotest.test_case "readings step 2: temporal proper (Lent I Monday, 2026-02-23)" `Quick test_readings_step2_temporal_proper; Alcotest.test_case "readings step 3: ferial resumption (Advent I Monday, 2025-12-01)" `Quick test_readings_step3_ferial_resumption; Alcotest.test_case "readings step 4: Common of Non-Virgins I (2038-03-06)" `Quick test_readings_step4_common_felicitas; Alcotest.test_case "readings step 4: Common of Non-Virgins II (2038-03-09)" `Quick test_readings_step4_common_frances; Alcotest.test_case "readings: displaced-Sunday feria pins M26 shape 2(b)'s KNOWN-WRONG walkback (2026-10-26)" `Quick test_readings_displaced_sunday_feria_known_divergent; Alcotest.test_case "RG87: Rogation Wednesday admitted (2024)" `Quick test_rogation_wednesday_admitted_2024; Alcotest.test_case "RG87/113: Rogation Wednesday yields to an impeded feast (2026)" `Quick test_rogation_wednesday_yields_to_a_feast_2026 ] )