summaryrefslogtreecommitdiff
path: root/test/test_oracle.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-17 22:38:01 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-17 22:38:01 +0200
commitc1776a07bfb41667d897c90914acea17f66f6510 (patch)
tree1da48b8fa15e3631a99710fa86b7702c910056a0 /test/test_oracle.ml
parent59e78716e5d7b13fd33f9c0245883c83712340e6 (diff)
downloadcolitur-c1776a07bfb41667d897c90914acea17f66f6510.tar.gz
colitur-c1776a07bfb41667d897c90914acea17f66f6510.zip
test(oracle): a third window, 2035, witnessing common-of-doctors
Step 4's blind spot is now closed as far as the method allows. 2038 witnessed two of the five Common-routed saints; isidore-of-seville is the third and the last that any year in 2005-2050 can reach, being observed only in 2008, 2035 and 2046. He is also the only saint routing through common-of-doctors, so that Common had never been compared against any external source in any window. Three independent agreements on it: the scan (Commune Doctorum, scan1:41878ff, 2 Tim. 4, 1-8 / Mt. 5, 13-19), colitur, and missalemeum's own 2035-04-04 row. Asserted by date in its own test rather than folded into an aggregate count, so a regression there cannot hide. The remaining two saints are unreachable by construction, not for want of a fixture: gregory-the-great and patrick both sit in March and are impeded by Lent's privileged ferias in every one of the 46 years the differential covers. The blind spot is closed to its limit, not closed absolutely, and the register says so. The comparator is generalised rather than copied -- compare_live takes a fixture and a year -- so a fourth window would cost a fixture and a count list. 2035 differs on 3 days, both families pre-existing and already cited. 2035-04-02/03 are the Joseph/Annunciation transfer pair landing in the opposite order from missalemeum's: neither stream loses a feast, the sequence differs, which is C14's own RG 96 collision finally getting an oracle window. 2035-12-30 is the Sunday within the Christmas Octave against colitur's numbered octave-day slug, C6's family. Both are recognised by slug rather than by date, so a year exhibiting only half the shape would surface as unexplained rather than be quietly absorbed. 393 tests green with the exhaustive sweep. Register: section 6.15.
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
+ ] )