summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-13 15:57:14 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-13 15:57:14 +0200
commitc7f9b66ffe0c265ab049afc8948317e9daded9e7 (patch)
treed86c083d1e10de3ac6ae9432395f3af9c5b85287
parent044aa0dccbfe76ac9afd299af6074296eeb2cca3 (diff)
downloadcolitur-c7f9b66ffe0c265ab049afc8948317e9daded9e7.tar.gz
colitur-c7f9b66ffe0c265ab049afc8948317e9daded9e7.zip
test(ef): reach RG 91 entry 27 through the real pipeline, end-to-end
Entry 27's band branch has been unreachable for the right reason since it was written: precedence_ef.ml's own comment on it acknowledged the row existed, but the one test exercising it built a hand-typed candidate, never a real Temporal_ef.temporal output, and nothing built the office itself. Closes that gap on both sides: - The band-table row now sources its candidate from Temporal_ef.temporal directly (of_temporal), the same review-finding-3 discipline the Ember/vigil rows already use, so a future regression in the office's own construction fails this row too, not only the unit-level test. - Two new resolve-level end-to-end tests, using the real band/ disposition/admit triple (not stubs): the office winning a real otherwise-unoccupied Saturday and admitting an ordinary commemoration alongside it (1 August 2026, Holy Machabees -- the task brief's own worked oracle example), and the office genuinely losing to a real competing feast and being omitted under RG 26, with no confusion from the one live data witness that also carries subject Bvm (12 September, Most Holy Name of Mary) -- proving RG 26's rank-keyed omission fires before any subject-keyed rule ever could. - Two golden pins mirroring the same two dates, checked by hand against `colitur day 2026` before being typed in, following this file's own "a golden test blesses whatever it is given, verified independently" discipline. The existing 2038-03-06 pin (RG 91 entry 24 outranking a Class4 candidate) is corrected in passing: that date is itself a Saturday, so the displaced candidate the pin's own omitted-list check names is now precisely entry 27's own shape, not entry 28's bare catch-all -- the win/lose outcome the pin proves is unchanged, only its own more precise citation. Mutation-tested (recorded in the task report): reverting is_bvm_saturday to a constant false reddens the dedicated unit test, the new end-to-end resolve test, and the 2026-08-01 golden pin, while leaving the 2026-09-12 "loses to a real feast" pin untouched, exactly as expected since that date's outcome never depended on the fix.
-rw-r--r--test/test_golden.ml83
-rw-r--r--test/test_precedence_ef.ml102
2 files changed, 179 insertions, 6 deletions
diff --git a/test/test_golden.ml b/test/test_golden.ml
index 594ea6b..bb4bcfc 100644
--- a/test/test_golden.ml
+++ b/test/test_golden.ml
@@ -851,8 +851,22 @@ let test_iii_class_feast_wins_class4_feria () =
"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 Septuagesima feria is in [omitted] (RG26), proving RG91 entry24>28 fired"
+ "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)
@@ -869,6 +883,63 @@ let test_iii_class_feast_wins_class4_feria () =
"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)
+
let suite =
( "golden pins (known-tricky years)",
[ Alcotest.test_case "Easter extreme: 1598 earliest (22 Mar, Gauss-verified)" `Quick
@@ -925,5 +996,13 @@ let suite =
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
+ `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
] )
diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml
index ed9a933..475ae6e 100644
--- a/test/test_precedence_ef.ml
+++ b/test/test_precedence_ef.ml
@@ -291,10 +291,21 @@ let cases =
cand ~origin:P.Sanctoral ~rank:V.Class3 ~layer:PE.universal_layer "vigil-of-st-lawrence",
260 );
(* Entry 27 -- RG 91 entry 27 (§4): an otherwise-unoccupied IV-class
- Saturday. *)
- ( "27 Office of the BVM on Saturday", off 62,
- cand ~rank:V.Class4 "ef-time-after-pentecost-1-sat",
- 270 );
+ Saturday. ef-bvm-saturday task: sourced from [Temporal_ef.temporal]'s
+ own real output (see [of_temporal], the same review-finding-3
+ discipline entry 18's/21's own rows above use), not a hand-typed
+ slug/rank pair -- this row used to be the one place in this whole
+ suite where [band]'s entry-27 branch was exercised by a value nothing
+ in [Temporal_ef.temporal] could actually produce (the office itself
+ was unbuilt): [band] read [rank = Class4 && weekday = Sat]
+ correctly, but nothing proved [temporal] ever handed it a candidate
+ shaped that way for the RIGHT reason. Now it does: [of_temporal (off
+ 62)] is 6 June 2026, a real otherwise-contested Time-after-Pentecost
+ Saturday (Norbert, Class3, wins the DAY outright in the real
+ pipeline -- irrelevant here, since this row tests [band] on the
+ TEMPORAL CANDIDATE alone, which [Temporal_ef.temporal] builds as the
+ BVM Saturday office regardless of what wins). *)
+ ( "27 Office of the BVM on Saturday (from Temporal_ef.temporal)", off 62, of_temporal (off 62), 270 );
(* Entry 28 -- RG 91 entry 28 (§4): the unqualified IV-class catch-all. *)
("28 IV-class feria", off 65, cand ~rank:V.Class4 "ef-time-after-pentecost-1-tue", 280);
(* Not an RG 91 row at all: a I-class candidate marked as a vigil, which
@@ -1421,6 +1432,81 @@ let test_ii_class_sunday_privileged_witness_admitted_end_to_end () =
[ ("ef-some-saint", "omitted: admission limit reached") ]
(List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted)
+(* RG 91 entry 27 / RG 78-79 (Caput IX, "De sancta Maria in sabbato") reached
+ end-to-end through the REAL pipeline -- this is THE hazard this task's own
+ brief names explicitly: {!PE.band}'s entry-27 branch has been reachable
+ only in isolation (the table-driven row above) since it was written, never
+ through a real [Temporal_ef.temporal] candidate winning an actual day, so
+ this test is checked for whether it exercises entry 27 for the RIGHT
+ reason -- proved by the mutation test recorded in the task report
+ (reverting temporal_ef.ml's own [is_bvm_saturday] branches back to the
+ generic ferial fallback reddens THIS test, not merely the [band]-table
+ row, which would still pass unchanged since it is sourced from real
+ [T.temporal] output either way).
+
+ 1 August 2026, matching the task brief's own worked example against the
+ oracle exactly: a Time-after-Pentecost Saturday, otherwise unoccupied but
+ for Holy Machabees (Commemoration_only, Class3, real data/ef/sanctoral.sexp
+ entry, 1 August) -- the office wins outright (band 270, ahead of Holy
+ Machabees's own [unclassified]) and the Commemoration_only loser still
+ rides along as an ordinary commemoration, the SAME shape the oracle's own
+ row for this date shows ("V Mass of the B. V. M. -- Salve, Sancta Parens",
+ commemorating Holy Machabees). *)
+let test_bvm_saturday_wins_and_commemorates_end_to_end () =
+ let date = mk 2026 8 1 in
+ let day_ctx = ctx date in
+ let bvm_saturday = of_temporal date in
+ let holy_machabees =
+ cand ~origin:P.Sanctoral ~rank:V.Class3 ~status:Cel.Commemoration_only ~layer:PE.universal_layer
+ "holy-machabees"
+ in
+ let resolution = P.resolve real_rules day_ctx ~temporal:bvm_saturday ~sanctoral:[ holy_machabees ] in
+ Alcotest.(check string) "the BVM Saturday office is observed, not Holy Machabees"
+ "ef-time-after-pentecost-9-saturday" (S.to_string resolution.P.observed.P.cel.Cel.slug);
+ Alcotest.(check string) "observed rank is class-4, unconditional" "class-4"
+ (V.rank_to_string resolution.P.observed.P.cel.Cel.rank);
+ Alcotest.(check string) "observed colour is white, overriding the season's own green" "white"
+ (Col.to_string resolution.P.observed.P.cel.Cel.colour);
+ Alcotest.(check bool) "observed subject is Bvm" true (resolution.P.observed.P.cel.Cel.subject = Sub.Bvm);
+ Alcotest.(check (list (pair string string))) "Holy Machabees still rides along as an ordinary commemoration"
+ [ ("holy-machabees", "Ordinary") ]
+ (List.map
+ (fun (c, p) -> (S.to_string c.P.cel.Cel.slug, match p with P.Privileged -> "Privileged" | P.Ordinary -> "Ordinary"))
+ resolution.P.commemorations);
+ Alcotest.(check int) "nothing omitted" 0 (List.length resolution.P.omitted)
+
+(* The other half of the SAME hazard: a real Saturday where RG 78's own
+ protasis is FALSE (a genuine sanctoral feast wins the day outright), so
+ the BVM-Saturday-shaped temporal candidate must lose, and be OMITTED under
+ RG 26 (a temporal Class4 non-vigil loser is never commemorated) exactly
+ like the plain ferial candidate it replaces always was -- proving [band]/
+ [disposition] need no special case for this office at all, the design
+ claim the task report makes explicitly. 12 September 2026 is a Saturday
+ where `most-holy-name-of-mary` (data/ef/adjustments.sexp's own [Set_subject
+ Bvm] entry, Class3 Feast) wins outright -- ALSO tagged [subject = Bvm],
+ the one live data witness that could in principle confuse a
+ subject-keyed disposition rule with RG 26's own rank-keyed one: this test
+ proves they do NOT collide (RG 26 fires first, unconditionally, on the
+ loser's own [rank = Class4], never reaching a subject comparison at all). *)
+let test_bvm_saturday_loses_to_a_real_feast_end_to_end () =
+ let date = mk 2026 9 12 in
+ let day_ctx = ctx date in
+ let bvm_saturday = of_temporal date in
+ let name_of_mary =
+ cand ~origin:P.Sanctoral ~rank:V.Class3 ~subject:Sub.Bvm ~layer:PE.universal_layer
+ "most-holy-name-of-mary"
+ in
+ let resolution = P.resolve real_rules day_ctx ~temporal:bvm_saturday ~sanctoral:[ name_of_mary ] in
+ Alcotest.(check string) "Most Holy Name of Mary is observed, not the BVM Saturday office"
+ "most-holy-name-of-mary" (S.to_string resolution.P.observed.P.cel.Cel.slug);
+ Alcotest.(check (list string)) "nothing is commemorated" []
+ (List.map (fun (c, _) -> S.to_string c.P.cel.Cel.slug) resolution.P.commemorations);
+ Alcotest.(check (list (pair string string)))
+ "the BVM-Saturday-shaped temporal candidate is omitted under RG26, not commemorated -- no Bvm-vs-Bvm \
+ confusion with RG112(a)-style subject logic"
+ [ ("ef-time-after-pentecost-15-saturday", "omitted: yielded to a higher day") ]
+ (List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted)
+
(* RG 16(a) (register §6.0) reached end-to-end through the REAL pipeline
([PE.band], [PE.disposition] AND [PE.admit] together, not any one of
them in isolation as this file's own hand-tagged rows test them
@@ -1895,6 +1981,14 @@ let suite =
"II-class Sunday override: RG109(b) witness admitted over an ordinary saint, end-to-end"
`Quick test_ii_class_sunday_privileged_witness_admitted_end_to_end;
Alcotest.test_case
+ "RG91 e27/RG78: the BVM Saturday office wins and commemorates Holy Machabees, end-to-end \
+ (2026-08-01)"
+ `Quick test_bvm_saturday_wins_and_commemorates_end_to_end;
+ Alcotest.test_case
+ "RG91 e27/RG78/RG26: the BVM Saturday office loses to a real feast and is omitted, end-to-end \
+ (2026-09-12)"
+ `Quick test_bvm_saturday_loses_to_a_real_feast_end_to_end;
+ Alcotest.test_case
"RG16(a): a Feast of the Lord suppresses the Sunday's own commemoration entirely, \
end-to-end (2028-08-06)"
`Quick test_rg16a_lord_feast_suppresses_sunday_end_to_end;