aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/test_differential.ml22
-rw-r--r--test/test_golden.ml20
-rw-r--r--test/test_oracle.ml51
-rw-r--r--test/test_rite_ef.ml95
4 files changed, 186 insertions, 2 deletions
diff --git a/test/test_differential.ml b/test/test_differential.ml
index 5093484..a4e550d 100644
--- a/test/test_differential.ml
+++ b/test/test_differential.ml
@@ -465,6 +465,27 @@ let jan_6_13_slug slug =
let nativity_octave_day_slugs =
[ "ef-nativity-octave-day-5"; "ef-nativity-octave-day-6"; "ef-nativity-octave-day-7" ]
+(* C18 (ef-sanctoral-audit, 2026-08-14): the closed set of colitur
+ [status = Feast] sanctoral slugs whose bootstrapped [colour] was
+ corrected against RG 124 (data/ef/adjustments.sexp's own audit-block
+ comment has the full citation and per-slug reasoning); every one of
+ these still carries lectio's OLD, uncorrected colour, so a row where
+ this is the ONLY colitur candidate observed for its own date diffs on
+ [Colour_f] alone whenever it wins the day (most years -- these are all
+ ordinary universal feasts, rarely impeded). Deliberately a literal list,
+ not a shape predicate, the same discipline C6/C14/C15/C16 already use:
+ a colour diff on any OTHER slug must still surface as unexplained. Eight
+ further audit corrections (prisca/peter/vitus/margaret/agapitus/liborii/
+ mark-i, all Commemoration_only, plus the new `barbara` Add) are NOT
+ listed here and need no predicate: [colitur_rows_2005_2050] emits only
+ the OBSERVED day's own record, and a [Commemoration_only] candidate can
+ never be observed (Precedence.resolve's own design), so their corrected
+ colours have no row in this comparison to explain. *)
+let audit_colour_corrected_slugs =
+ [ "conversion-of-st-paul"; "chair-of-st-peter"; "john-of-san-fecundo"; "ephrem-of-syria";
+ "julia-of-falconieri"; "john-gualbert"; "camillus-de-lellis"; "jerome-emiliani"; "apollinaris";
+ "martha"; "alphonsus-liguori"; "augustine"; "rose-of-lima"; "josaphat" ]
+
(* C14 (ef-rebootstrap fixture refresh, 2026-08-12; replaces the closed C9,
see data/ef/expected-divergences.sexp's own C14 note for the full RG
citation): the exact 3 civil days, across the whole 2005-2050 window,
@@ -620,6 +641,7 @@ let layer_c_reason (l : row) (c : row) diffs =
&& String.equal c.slug "ef-holy-name"
then Some "C16"
else if is_bvm_saturday_row c diffs then Some "C17"
+ else if diffs = [ Colour_f ] && List.mem c.slug audit_colour_corrected_slugs then Some "C18"
else None
(* ---------------------------------------------------------------------- *)
diff --git a/test/test_golden.ml b/test/test_golden.ml
index 7b461bf..a873738 100644
--- a/test/test_golden.ml
+++ b/test/test_golden.ml
@@ -493,9 +493,25 @@ let test_ember_ferias_commemorated_when_impeded () =
[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. *)
+ 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 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=[]"
diff --git a/test/test_oracle.ml b/test/test_oracle.ml
index 3a9e499..c1d0e6a 100644
--- a/test/test_oracle.ml
+++ b/test/test_oracle.ml
@@ -910,6 +910,52 @@ let m19_commemoration_matches (c : colitur_row) =
| [ (slug, _, _, _) ] -> String.equal slug "commemoration-of-st-peter"
| _ -> false
+(* M21 -- ef-sanctoral-audit task (2026-08-14): the SAME closed 14-slug list
+ test_differential.ml's own [audit_colour_corrected_slugs] uses (RG 124,
+ data/ef/adjustments.sexp's own audit-block comment has the full
+ citation), now checked against THIS window's own oracle. Two of the
+ fourteen (`apollinaris`, 23 July; `josaphat`, 14 November) and one
+ further entry not on the Feast-status list at all (`chair-of-st-peter`,
+ 22 February, a Feast in its own right, RG124(b)) disagree with
+ missalemeum's own colour TOO, not merely lectio's -- a SECOND,
+ independent data source repeating the same defect (Apollinaris and
+ Josaphat are each martyr-bishops, RG 124(e); Peter's Chair is an
+ Apostle's own feast day, RG 124(b) -- both scan-verified word for word,
+ data/ef/adjustments.sexp's own comment), so this is not a case of
+ "missalemeum corroborates colitur, only lectio disagrees": the primary
+ TEXT is what decides it, and missalemeum is simply wrong on these three
+ the same way lectio is on all fourteen. [Comm_identity_unresolved] is
+ allowed alongside on 22 February specifically: that date's OTHER
+ commemoration (the ordinary Lenten feria RG 110 rides in alongside Paul)
+ is TEMPORAL-origin and already unresolved for identity, the same
+ pre-existing gap [M15]/[M18] elsewhere in this file document -- a
+ different axis, not something this entry's own citation explains, so it
+ is admitted by the subset check rather than folded into the citation. *)
+let m21_colour_slugs =
+ [ "conversion-of-st-paul"; "chair-of-st-peter"; "john-of-san-fecundo"; "ephrem-of-syria";
+ "julia-of-falconieri"; "john-gualbert"; "camillus-de-lellis"; "jerome-emiliani"; "apollinaris";
+ "martha"; "alphonsus-liguori"; "augustine"; "rose-of-lima"; "josaphat" ]
+
+(* M22 -- ef-sanctoral-audit task: `barbara` (4 December, data/ef/
+ adjustments.sexp's own new `Add`) is a genuine DATA GAP in missalemeum
+ too, the identical shape M1/M3/M8/M10/M19 above already document (each
+ "missalemeum does not implement X"): both years' own 4 December row
+ shows only the Advent feria's own temporal commemoration, no Barbara at
+ all, not even displaced -- missalemeum never constructed a candidate for
+ her either, the same absence lectio's own tridentine-calendar.ini has
+ (data/ef/adjustments.sexp's own `Add barbara` comment). Identity-gated
+ the same way [M19] is (coordinator finding F2): the predicate requires
+ colitur's own admitted set to be EXACTLY the temporal feria plus
+ `barbara`, not merely that SOME count diff exists on this date, so a
+ future unrelated regression on 4 December cannot silently hide behind
+ this citation. *)
+let m22_dates = [ "2026-12-04"; "2027-12-04" ]
+
+let m22_commemoration_matches (c : colitur_row) =
+ match List.map (fun (slug, _, _, _) -> slug) c.c_commemorations with
+ | [ a; b ] -> (String.equal a "barbara") <> (String.equal b "barbara")
+ | _ -> false
+
(* [_o] (the oracle's own row) is unused now that M2 -- its one reader, via
[o.o_title] -- is closed/removed (see the comment above [m1_dates]):
every remaining predicate below reads only [c]/[diffs]. Kept as a named,
@@ -965,6 +1011,11 @@ let layer_m_reason (c : colitur_row) (_o : oracle_row) diffs =
else if List.mem c.c_date m19_dates && diffs = [ Comm_presence ] && m19_commemoration_matches c then
Some "M19"
else if
+ List.mem c.c_observed_slug m21_colour_slugs && diffs = [ Colour_f ]
+ then Some "M21"
+ else if List.mem c.c_date m22_dates && diffs = [ Comm_count ] && m22_commemoration_matches c then
+ Some "M22"
+ else if
List.mem c.c_date m20_dates
&& subset diffs [ Comm_identity_mismatch; Observed_identity_unresolved ]
&& m20_commemoration_matches c
diff --git a/test/test_rite_ef.ml b/test/test_rite_ef.ml
index 6cd8709..67b42ce 100644
--- a/test/test_rite_ef.ml
+++ b/test/test_rite_ef.ml
@@ -166,6 +166,97 @@ let test_eusebius_confessor_colour_corrected () =
true
(e.Layer.cel.Cel.colour = Colour.White)
+(* ef-sanctoral-audit task (2026-08-14): a full extraction of the primary
+ CALENDARIUM (both photographic scans, page images read directly, not
+ their OCR text layers) against all 327 base entries plus the two prior
+ overlay Adds -- data/ef/adjustments.sexp's own audit-block comment has
+ the full method and RG 124 citation; docs/research/rules-register.md's
+ audit rewrite and .superpowers/sdd/2026-08-12-colitur-rg16a/sanctoral-
+ audit-report.md have the full findings. Same discipline as
+ [test_eusebius_confessor_colour_corrected] above (its own predecessor,
+ same root cause): a typo'd slug or a reverted directive fails THIS test,
+ not only silently changes unread data. One table, all eleven [Feast]
+ colour corrections plus the seven [Commemoration_only] ones (inert to
+ [Precedence_ef.band]/[admit] today -- colour is read nowhere in either,
+ confirmed by grep -- but real for `colitur day`'s own printed output the
+ moment either entry is ever observed/commemorated). *)
+let test_audit_colours_corrected () =
+ let layer = real_layer () in
+ let check_colour slug expected reason =
+ match Layer.find layer (Slug.of_string_exn slug) with
+ | None -> Alcotest.failf "slug %s not found in the overlaid layer" slug
+ | Some e ->
+ Alcotest.(check bool) (Printf.sprintf "%s: %s" slug reason) true (e.Layer.cel.Cel.colour = expected)
+ in
+ (* RG 124(e): a Martyr's own martyrdom is red -- these SIX were White.
+ Three more were set Red by the audit and REVERTED by the fix-round
+ review: conversion-of-st-paul and chair-of-st-peter are NAMED, by name
+ and by date, in RG 120(f)'s own enumeration of WHITE, fifteen lines
+ above the RG 124(b) the audit cited; and `peter` (25 Jan) rested on
+ "match the host day's Red", whose host is white by that same clause.
+ They are asserted White below, where the reverted values belong. *)
+ List.iter
+ (fun (slug, reason) -> check_colour slug Colour.Red reason)
+ [ ("prisca", "Virg. et Mart., 18 Jan -- RG124(e); lectio's own NAME dropped 'et Mart.', so its name is the defective field, not its colour");
+ ("vitus", "Ss. ... Mm., 15 Jun -- RG124(e)");
+ ("margaret", "Virg. et Mart., 20 Jul (comm) -- RG124(e)");
+ ("apollinaris", "Ep. et Mart., 23 Jul -- RG124(e)");
+ ("agapitus", "Mart., 18 Aug -- RG124(e)");
+ ("josaphat", "Ep. et Mart., 14 Nov -- RG124(e)") ];
+ (* RG 120(e), "Sanctorum non Martyrum" -- a POSITIVE rule, four lines
+ above the one the audit misapplied. These were cited to "RG 117's
+ five-colour residual", a negative inference from the red list's
+ exhaustiveness; the outcome was right and the citation was weaker than
+ the Missal's own. The first three are the fix-round reverts, white by
+ RG 120(f)'s own naming rather than by (e). *)
+ List.iter
+ (fun (slug, reason) -> check_colour slug Colour.White reason)
+ [ ("conversion-of-st-paul", "25 Jan -- NAMED white by RG120(f), 'Conversionis S. Pauli (25 ianuarii)'");
+ ("chair-of-st-peter", "22 Feb -- NAMED white by RG120(f), 'Cathedrae S. Petri (22 februarii)'");
+ ("peter", "25 Jan commemoration -- its host is white by RG120(f), so the audit's own precedent yields White");
+ ("john-of-san-fecundo", "Conf. only, 12 Jun");
+ ("ephrem-of-syria", "Conf. et Eccl. Doct. only, 18 Jun");
+ ("julia-of-falconieri", "Virg. only, 19 Jun");
+ ("john-gualbert", "Abb. (Conf.) only, 12 Jul");
+ ("camillus-de-lellis", "Conf. only, 18 Jul");
+ ("jerome-emiliani", "Conf. only, 20 Jul");
+ ("liborii", "Ep. et Conf. only, 23 Jul (comm)");
+ ("martha", "Virg. only, 29 Jul");
+ ("alphonsus-liguori", "Ep., Conf. et Eccl. Doct. only, 2 Aug");
+ ("augustine", "Ep., Conf. et Eccl. Doct. only, 28 Aug");
+ ("rose-of-lima", "Virg. only, 30 Aug");
+ ("mark-i", "Papae et Conf. only (Pope Mark I, not the Evangelist), 7 Oct (comm)") ]
+
+(* `barbara` (4 December): a genuine DATA GAP, not a colour correction --
+ present in both photographic scans as a Commemoratio nested under
+ Peter Chrysologus's own entry, absent from data/ef/sanctoral.sexp AND
+ from lectio's own tridentine-calendar.ini (same upstream-gap shape as
+ the ef-rebootstrap task's five: agnes-secundo/boniface-martyr/
+ eusebius-confessor/evaristus/theodore). Added via data/ef/
+ adjustments.sexp's own new `Add` directive. *)
+let test_barbara_added () =
+ let layer = real_layer () in
+ match Layer.find layer (Slug.of_string_exn "barbara") with
+ | None -> Alcotest.fail "slug barbara not found in the overlaid layer (ef-sanctoral-audit Add missing?)"
+ | Some e ->
+ Alcotest.(check bool) "barbara: 4 December" true
+ (match e.Layer.date with Date_spec.Fixed { month = 12; day = 4 } -> true | Date_spec.Fixed _ -> false);
+ Alcotest.(check bool) "barbara: Commemoration_only (no separate feast row in the calendarium, a bare \
+ \"Commemoratio\" nested under Peter Chrysologus)"
+ true (e.Layer.cel.Cel.status = Cel.Commemoration_only);
+ Alcotest.(check bool) "barbara: Class3 (the same bootstrap-inference convention every OTHER \
+ Commemoration_only entry in this file uses -- the calendarium gives no numeral \
+ for any commemoration, hers included)"
+ true (e.Layer.cel.Cel.rank = V.Class3);
+ Alcotest.(check bool) "barbara: Red (RG124(e), \"Virg. et Mart.\")" true
+ (e.Layer.cel.Cel.colour = Colour.Red);
+ Alcotest.(check bool) "barbara: appears as a commemoration on 4 December in real output" true
+ (let days = Cal.year Rite_ef.context layer 2026 in
+ Array.to_list days
+ |> List.exists (fun d ->
+ Date.compare d.LD.date (mk 2026 12 4) = 0
+ && List.exists (fun (c, _) -> slug_of c = "barbara") d.LD.commemorations))
+
(* Coordinator review, finding 2, reproduced through the project's OWN
extension path (an overlay), the same way the reviewer found it: adding
an I-class feast on 25 December (competing against, and losing to, the
@@ -422,6 +513,10 @@ let suite =
`Quick test_rg16a_subject_retag_in_effect;
Alcotest.test_case "ef-rebootstrap fix round 1 (F3): eusebius-confessor is White, not lectio's Red" `Quick
test_eusebius_confessor_colour_corrected;
+ Alcotest.test_case "ef-sanctoral-audit: 18 colour corrections in effect (RG120(e)/124(e)); 3 reverted per RG120(f)" `Quick
+ test_audit_colours_corrected;
+ Alcotest.test_case "ef-sanctoral-audit: barbara (4 Dec) added, a genuine data gap" `Quick
+ test_barbara_added;
Alcotest.test_case "RG96 search does not raise at the domain ceiling (real data)" `Quick
test_transfer_search_does_not_raise_at_domain_ceiling;
Alcotest.test_case "no transfer ever lands inside [Easter, Easter+7], 2005-2050" `Quick