aboutsummaryrefslogtreecommitdiff
path: root/test/test_oracle.ml
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_oracle.ml')
-rw-r--r--test/test_oracle.ml122
1 files changed, 119 insertions, 3 deletions
diff --git a/test/test_oracle.ml b/test/test_oracle.ml
index e90a45a..ae82b31 100644
--- a/test/test_oracle.ml
+++ b/test/test_oracle.ml
@@ -1819,6 +1819,26 @@ let classify_2038 (c : colitur_row) (o : oracle_row) diffs =
else if c.c_observed_slug = "sts-felicitas-perpetua" then Some "PERPETUA-COMMON (register 6.8)"
else if c.c_observed_slug = "ef-nativity" then Some "CHRISTMAS-MULTI-MASS (M27)"
else if first_is "Dan 14:27, 28-42" then Some "MISSAL-TWO-PART-CITATION (register 6.9)"
+ (* Both saints transferred out of Holy Week, landing on adjacent days in the
+ opposite ORDER from missalemeum's: colitur puts the Annunciation first,
+ the oracle puts Joseph first. Neither stream loses a feast -- the pair is
+ the same, the sequence differs. This is the collision C14 already cites on
+ the differential side (Joseph's own transfer against the Annunciation's
+ fixed "sedes propria", RG 96); it simply had no oracle window until a
+ live-capture year happened to contain it. Recognised by the pair of
+ slugs, not by date, so a year where only ONE of them moved would not
+ match and would surface as unexplained. *)
+ else if
+ c.c_observed_slug = "annunciation-of-the-blessed-virgin-mary"
+ || c.c_observed_slug = "joseph-spouse-of-the-bl-virgin-mary"
+ then Some "JOSEPH-ANNUNCIATION-TRANSFER-ORDER (C14's own collision)"
+ (* RG 69's Sunday within the Octave of the Nativity against colitur's own
+ numbered octave-day slug -- C6's family on the differential side, and the
+ same disagreement about which office a late-December Sunday carries. *)
+ else if
+ String.length c.c_observed_slug > 19
+ && String.sub c.c_observed_slug 0 19 = "ef-nativity-octave-"
+ then Some "NATIVITY-OCTAVE-SUNDAY (C6's family, RG 69)"
else None
let diffs_2038 (c : colitur_row) (o : oracle_row) =
@@ -1833,9 +1853,13 @@ let diffs_2038 (c : colitur_row) (o : oracle_row) =
| _ -> ());
List.rev !d
-let compare_2038 () =
- let oracle = List.map oracle_row_of_line (read_lines fixture_2038_path) in
- let colitur = colitur_rows ~from_year:2038 ~to_year:2038 in
+(* Parameterised over (fixture, year) so a second live-capture year costs a
+ fixture and a count list, not a copy of the comparator. 2035 was added for
+ `isidore-of-seville`, the last Common-routed saint reachable in any year the
+ differential covers. *)
+let compare_live ~fixture ~year =
+ let oracle = List.map oracle_row_of_line (read_lines fixture) in
+ let colitur = colitur_rows ~from_year:year ~to_year:year in
let by_date = Hashtbl.create 400 in
List.iter (fun (c : colitur_row) -> Hashtbl.replace by_date c.c_date c) colitur;
List.filter_map
@@ -1847,6 +1871,8 @@ let compare_2038 () =
if diffs = [] then None else Some (o.o_date, diffs, classify_2038 c o diffs, c, o))
oracle
+let compare_2038 () = compare_live ~fixture:fixture_2038_path ~year:2038
+
let test_2038_fixture_checksum () =
Alcotest.(check string) "2038 fixture SHA-256 matches its provenance note" fixture_2038_sha256
(sha256_of_file fixture_2038_path)
@@ -1943,3 +1969,93 @@ let suite_2038 =
Alcotest.test_case "the two Common-route days: Frances agrees, Perpetua is the known divergence"
`Quick test_2038_common_route_days
] )
+
+(* ====================================================================== *)
+(* The 2035 oracle extension (2026-08-17) *)
+(* ====================================================================== *)
+
+(* A THIRD comparison window, and the one that finally witnesses the last
+ reachable Common-routed saint.
+
+ Register §6.7 recorded step 4 -- the Common route -- as having no external
+ witness at all. 2038 (§6.9) closed two of the five saints,
+ `sts-felicitas-perpetua` and `frances-rome`. `isidore-of-seville` is the
+ third and last that ANY year in 2005-2050 can witness: he is the observed
+ office on 2008-04-04, 2035-04-04 and 2046-04-04 and nowhere else, and he is
+ the only saint routing through `common-of-doctors`, which no other fixture
+ touches. The remaining two, `gregory-the-great` and `patrick`, are never
+ the observed office in any of those 46 years -- both sit in March and are
+ impeded by Lent's privileged ferias every year -- so no fixture in that
+ range can reach them by construction, and this is as far as the method
+ goes.
+
+ Same provenance shape as 2038: a live capture, kept separate from the
+ snapshot-derived 2026-2027 fixture because the endpoint has drifted from
+ it. Same narrower comparison too (rank, colour, Epistle, Gospel), for the
+ same reason -- the commemoration and observed-identity axes are built round
+ a date-literal allow-list specific to 2026-2027. *)
+
+let fixture_2035_path = "fixtures/missalemeum-ef-2035.txt"
+let fixture_2035_sha256 = "39b000827f45cb0c2c712625fd9514a8c0e71e8a94fc9f69df4a97d91f90014d"
+let compare_2035 () = compare_live ~fixture:fixture_2035_path ~year:2035
+
+let test_2035_fixture_checksum () =
+ Alcotest.(check string) "2035 fixture SHA-256 matches its provenance note" fixture_2035_sha256
+ (sha256_of_file fixture_2035_path)
+
+let test_2035_dates_align () =
+ let oracle = List.map oracle_row_of_line (read_lines fixture_2035_path) in
+ let colitur = colitur_rows ~from_year:2035 ~to_year:2035 in
+ Alcotest.(check int) "oracle is 365 rows" 365 (List.length oracle);
+ Alcotest.(check (list string)) "dates align 1:1"
+ (List.map (fun (o : oracle_row) -> o.o_date) oracle)
+ (List.map (fun (c : colitur_row) -> c.c_date) colitur)
+
+(* The whole point of this fixture. `common-of-doctors` has never been
+ compared against any external source, in any window, until now: it is the
+ one Common that only `isidore-of-seville` routes through, and he is the
+ observed office on exactly three days in 2005-2050. The scan says
+ "2 Tim. 4, 1-8" / "Mt. 5, 13-19" (Commune Doctorum, scan1.txt:41878 ff);
+ colitur says the same; this asserts missalemeum does too. *)
+let test_2035_isidore_common_of_doctors () =
+ match List.find_opt (fun (d, _, _, _, _) -> d = "2035-04-04") (compare_2035 ()) with
+ | None -> ()
+ | Some (_, diffs, _, c, o) ->
+ Alcotest.failf
+ "2035-04-04 (isidore-of-seville, the ONLY common-of-doctors witness) should agree: %s -- colitur \
+ first=%s gospel=%s, oracle title=%s first=%s gospel=%s"
+ (String.concat "," (List.map field_name diffs))
+ (Option.value c.c_first ~default:"-")
+ (Option.value c.c_gospel ~default:"-")
+ o.o_title
+ (Option.value o.o_first ~default:"-")
+ (Option.value o.o_gospel ~default:"-")
+
+let test_2035_every_difference_is_classified () =
+ let unexplained =
+ compare_2035 ()
+ |> List.filter_map (fun (date, diffs, cls, c, o) ->
+ match cls with
+ | Some _ -> None
+ | None ->
+ Some
+ (Printf.sprintf "%s: %s -- colitur=(%s rank=%d colour=%c first=%s) oracle=(%s rank=%d first=%s)"
+ date
+ (String.concat "," (List.map field_name diffs))
+ c.c_observed_slug c.c_rank c.c_colour
+ (Option.value c.c_first ~default:"-")
+ o.o_title o.o_rank
+ (Option.value o.o_first ~default:"-")))
+ in
+ Alcotest.(check (list string)) "every 2035 difference falls in a named, adjudicated class" [] unexplained
+
+let suite_2035 =
+ ( "oracle (missalemeum, EF, 2035 -- common-of-doctors)",
+ [ Alcotest.test_case "2035 fixture SHA-256 matches its provenance note" `Quick
+ test_2035_fixture_checksum;
+ Alcotest.test_case "streams are 365 rows each, dates aligned 1:1" `Quick test_2035_dates_align;
+ Alcotest.test_case "isidore-of-seville: the only common-of-doctors witness agrees" `Quick
+ test_2035_isidore_common_of_doctors;
+ Alcotest.test_case "every difference falls in a named, adjudicated class" `Quick
+ test_2035_every_difference_is_classified
+ ] )