aboutsummaryrefslogtreecommitdiff
path: root/test/test_golden.ml
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_golden.ml')
-rw-r--r--test/test_golden.ml174
1 files changed, 173 insertions, 1 deletions
diff --git a/test/test_golden.ml b/test/test_golden.ml
index 8d33e29..e9b3ec5 100644
--- a/test/test_golden.ml
+++ b/test/test_golden.ml
@@ -55,6 +55,7 @@ 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
@@ -170,6 +171,42 @@ let describe (day : (V.season, V.rank) LD.t) =
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
@@ -1122,6 +1159,128 @@ let test_major_litanies_transfer_2011_easter_monday () =
"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"
+
let suite =
( "golden pins (known-tricky years)",
[ Alcotest.test_case "Easter extreme: 1598 earliest (22 Mar, Gauss-verified)" `Quick
@@ -1199,5 +1358,18 @@ let suite =
`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
+ 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
] )