aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/test_golden.ml16
-rw-r--r--test/test_oracle.ml81
-rw-r--r--test/test_precedence_ef.ml68
3 files changed, 137 insertions, 28 deletions
diff --git a/test/test_golden.ml b/test/test_golden.ml
index c5aa65a..80e2c9d 100644
--- a/test/test_golden.ml
+++ b/test/test_golden.ml
@@ -434,11 +434,21 @@ let test_ember_ferias_commemorated_when_impeded () =
comms=[ef-advent-ember-fri:privileged] in=- out=[]";
(* 1902-02-22: Lent Ember Saturday (RG91 entry 18, II class) impeded by
the Chair of St Peter (II class, universal, entry 16). Same RG24/
- RG109(e) mandate. *)
- check ~msg:"1902-02-22: Lent Ember Saturday, impeded, MUST be commemorated (RG24) and is privileged (RG109e)"
+ RG109(e) mandate. ALSO, ef-holyname-rg110 task: RG 110's own
+ inseparable Peter/Paul commemoration -- "in Officio ... S. Petri semper
+ fit commemoratio S. Pauli" -- fires unconditionally whenever
+ [chair-of-st-peter] is observed, uncapped by RG 111's own admission
+ count, so `+paul` now rides alongside the Ember feria's own
+ commemoration rather than being displaced by it (precedence_ef.ml's own
+ [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. *)
+ 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"
1902 2 22
"1902-02-22 saturday season=lent week=1 slug=chair-of-st-peter rank=class-2 colour=white subject=saint \
- comms=[ef-lent-ember-sat:privileged] in=- out=[]"
+ comms=[ef-lent-ember-sat:privileged,paul:ordinary] in=- out=[]"
let test_iv_class_ferias_never_commemorated () =
(* 2026-07-22: an ordinary Time-after-Pentecost feria (Class4, RG91 entry
diff --git a/test/test_oracle.ml b/test/test_oracle.ml
index 35d4501..370eec0 100644
--- a/test/test_oracle.ml
+++ b/test/test_oracle.ml
@@ -599,23 +599,23 @@ let m10_dates = [ "2026-11-30"; "2027-11-30"; "2026-12-08"; "2027-12-08" ]
own full note and the task report. *)
let m11_dates = [ "2026-12-26"; "2026-12-28"; "2027-12-27"; "2027-12-28" ]
-(* M12 -- RG 110, primary text: "In Officio et Missa S. Petri semper fit
- commemoratio S. Pauli, et vicissim" -- in the Office and Mass of EITHER
- Peter or Paul, a commemoration of the OTHER is ALWAYS made (the
- "inseparable commemoration"), uncapped by RG 111's ordinary admission
- count ("in numero orationum computando, pro unica habeantur" -- counted
- as one for counting purposes, i.e. it rides alongside whatever RG 111
- already admits). Unimplemented in this codebase -- confirmed by the one
- row in this window where it is visible: 22 February 2027 (Chair of
- St Peter) shows only the privileged Lent feria commemorated in colitur,
- while missalemeum shows that AND "St. Paul". A genuine, primary-cited
- feature gap -- verdict missalemeum, register §6 open item. Real but
- NARROW: every other Peter/Paul office in this window (29 June, both
- years; 1 August M4-adjacent dates were checked and found clean) either
- had no room for the extra commemoration to become visible against this
- comparator's axes, or fell on a day this predicate does not otherwise
- touch -- see the task report for the specific check. *)
-let m12_dates = [ "2027-02-22" ]
+(* M12 -- CLOSED (ef-holyname-rg110 task): RG 110 is now built
+ (precedence_ef.ml's own [rg110_additions]/[rg110_companion_slug]), and
+ this window's one visible instance -- 22 February 2027 -- no longer
+ diverges from missalemeum on [Comm_count] at all: colitur now shows the
+ privileged Lent feria's own commemoration AND "St. Paul", same COUNT
+ (two) as missalemeum. Removed rather than kept as a dead 0-row citation,
+ the SAME shape M17's own removal already established (this file's own
+ header): the count pin now enforces that this exact divergence cannot
+ silently reappear. NOT closed with zero remaining difference, though --
+ see M15's own widened date list immediately below: once count agrees,
+ IDENTITY comparison is reached for the first time on this date, and
+ trips a SEPARATE, pre-existing, unrelated comparator limit (one of
+ colitur's two admitted commemorations, [ef-lent-2-monday], is
+ TEMPORAL-origin and carries no English name) -- a newly-exposed
+ instance of M15's own gap, not a new one, folded into M15's date list
+ rather than kept here under RG 110's own citation, which no longer
+ explains ANY part of this row's remaining diff. *)
(* M13 -- OPEN, NOT adjudicated (the brief's own explicit permission,
"say so as an open item rather than absorbing it"). 19 March 2027: St
@@ -647,13 +647,13 @@ let m13_dates = [ "2027-03-19" ]
either engine is wrong about: a genuine LIMIT of this comparator, honestly
counted rather than silently passed (the brief's own explicit
instruction: "a day whose commemoration cannot be matched must be
- visibly counted and reported, not quietly passed"). On each of these 19
+ visibly counted and reported, not quietly passed"). On 19 of these 20
rows, colitur's own admitted commemoration is TEMPORAL-origin (an
impeded Advent/Lent feria) -- Rite_ef.Temporal_ef's own [build]
(temporal_ef.ml) never sets a celebration's [names] field, so there is no
English string on colitur's side to compare against missalemeum's title
text at all (this file's own header, "THE MAPPING, AND EXACTLY WHAT IT
- CANNOT RESOLVE"). Every one of these 19 oracle titles reads as a plain
+ CANNOT RESOLVE"). Every one of those 19 oracle titles reads as a plain
prose description of the SAME temporal ferial slot colitur independently
computes for that date (e.g. 2 Dec 2026: oracle "Feria IV after I Sunday
of Advent" against colitur's own [ef-advent-1-wednesday]; 4 Dec 2027:
@@ -664,12 +664,25 @@ let m13_dates = [ "2027-03-19" ]
unresolved. Fixing this at the ROOT (giving every temporal-cycle
candidate an English name) is a data/lectionary-bootstrap task, not
something this comparator can do for itself -- register §6, "RG 113
- tie-break" section's own neighbour, records it as an open item. *)
+ tie-break" section's own neighbour, records it as an open item.
+
+ ADDED, ef-holyname-rg110 task: 2027-02-22 -- the closed M12's own date,
+ above. NOT the same shape as the other 19 (colitur admits TWO
+ commemorations there, not one -- [paul], sanctoral-origin and
+ resolvable, and [ef-lent-2-monday], temporal-origin and not): the
+ comparator's own [identity_diff] bails out to [Comm_identity_unresolved]
+ the moment ANY admitted commemoration is unresolvable, regardless of how
+ many others resolve cleanly (test_oracle.ml's own [identity_diff],
+ "[List.exists] ... name = None"), so this row reaches the identical
+ diagnosis for the identical structural reason, once RG 110 stopped
+ [Comm_count] from masking it. Genuinely newly-EXPOSED by this task's own
+ fix, not newly-CAUSED by it: the underlying gap (no English name for a
+ temporal-cycle candidate) is exactly M15's own pre-existing one. *)
let m15_dates =
[ "2026-02-24"; "2026-03-19"; "2026-03-25"; "2026-12-02"; "2026-12-03"; "2026-12-04";
- "2026-12-07"; "2026-12-11"; "2026-12-21"; "2027-02-24"; "2027-12-02"; "2027-12-03";
- "2027-12-04"; "2027-12-06"; "2027-12-07"; "2027-12-11"; "2027-12-13"; "2027-12-16";
- "2027-12-21" ]
+ "2026-12-07"; "2026-12-11"; "2026-12-21"; "2027-02-22"; "2027-02-24"; "2027-12-02";
+ "2027-12-03"; "2027-12-04"; "2027-12-06"; "2027-12-07"; "2027-12-11"; "2027-12-13";
+ "2027-12-16"; "2027-12-21" ]
(* M16 -- Task B: a genuine IDENTITY mismatch, both sides otherwise agreeing
on rank/colour/count/presence. 27 March 2026 (Friday of Passion Week):
@@ -766,6 +779,26 @@ let m16_dates = [ "2026-03-27" ]
bootstrap task (Plan 4), not something this comparator can do for itself
-- register §6 tracks it, the same open item
[M15]'s own note already points to. *)
+(* M19 -- ef-holyname-rg110 task: RG 110's OTHER direction, 30 June (this
+ window's two instances -- both years -- of
+ [in-commemoratione-sancti-pauli-apostoli], data/ef/adjustments.sexp's
+ own `Add commemoration-of-st-peter` directive; see that file's own
+ citation for the full scan quote). Unlike 22 February above,
+ missalemeum's own row for both dates shows an EMPTY commemorations array
+ ("St. Peter" absent, and not even listed as "displaced" -- nothing
+ competes for the slot on either side, so there is no candidate for
+ missalemeum's own engine to have rejected, only one it never
+ constructed): missalemeum has the SAME gap this task's own scan found in
+ lectio's source data (`~/git/projects/lectio/internal/caldata/
+ tridentine-calendar.ini` has no 06-30 companion entry either) -- a
+ genuine feature gap, verdict colitur, the SAME shape as M1/M3/M8/M10
+ above (each already "missalemeum does not implement X"), not a
+ citation-count coincidence: RG 110's own text is unconditional ("in
+ Officio et Missa S. Petri semper fit commemoratio S. Pauli, ET
+ VICISSIM"), and the calendarium's own June table states the SAME
+ pattern already built for the other two pairs, word for word. *)
+let m19_dates = [ "2026-06-30"; "2027-06-30" ]
+
let layer_m_reason (c : colitur_row) (o : oracle_row) diffs =
if diffs = [] then None
(* M1's own subset widened (this task): colitur's observed day on both
@@ -795,7 +828,6 @@ let layer_m_reason (c : colitur_row) (o : oracle_row) diffs =
else if List.mem c.c_date m8_dates && diffs = [ Comm_presence ] then Some "M8"
else if List.mem c.c_date m10_dates && diffs = [ Comm_presence ] then Some "M10"
else if List.mem c.c_date m11_dates && diffs = [ Comm_presence ] then Some "M11"
- else if List.mem c.c_date m12_dates && diffs = [ Comm_count ] then Some "M12"
(* M13's own subset widened AGAIN (this task, following the SAME pattern
Task B's own widening comment below records): colitur's observed
celebration here is Joseph, SANCTORAL-origin, so its name IS
@@ -818,6 +850,7 @@ let layer_m_reason (c : colitur_row) (o : oracle_row) diffs =
&& subset diffs [ Comm_identity_mismatch; Observed_identity_unresolved ]
then Some "M16"
else if diffs = [ Observed_identity_unresolved ] then Some "M18"
+ else if List.mem c.c_date m19_dates && diffs = [ Comm_presence ] then Some "M19"
else None
(* ---------------------------------------------------------------------- *)
diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml
index d873e34..af7f65e 100644
--- a/test/test_precedence_ef.ml
+++ b/test/test_precedence_ef.ml
@@ -1016,6 +1016,33 @@ let sixtus =
UNIVERSALLY), so the two values coinciding is the faithful shape, not a
simplification that dodges the new parameter. The last two rows are
where they genuinely differ -- see their own comment. *)
+(* RG 110 (§4, Caput XIV): candidates built with the REAL trigger/companion
+ slugs {!PE.rg110_companion_slug} matches on -- unlike every other
+ [admit_cases] candidate above, which is deliberately built with a
+ SYNTHETIC slug {!PE.band}'s 28 branches (and this file's own RG 110
+ lookup) cannot recognise, these three rows need [PE.admit] to recognise
+ the slug itself, so the real ones are used directly. [~status:
+ Cel.Commemoration_only] on the companions matches the real data shape
+ (data/ef/sanctoral.sexp's own [peter]/[paul];
+ data/ef/adjustments.sexp's own [commemoration-of-st-peter]) even though
+ [admit] itself never reads [status] -- only [Precedence.resolve]'s own
+ partition does, upstream of [admit] -- kept for a reader's sake, not a
+ test requirement. *)
+let chair_of_st_peter_synth = cand ~rank:V.Class2 "chair-of-st-peter"
+let paul_companion_synth = cand ~rank:V.Class3 ~status:Cel.Commemoration_only "paul"
+
+(* Any real Lent/Ember feria's own shape (a Class3, PRIVILEGED, temporal-
+ origin candidate) -- {!PE.rg110_companion_slug} does not match this slug,
+ so it is a neutral bystander in [admit]'s own normal (pre-RG110) contest,
+ exactly like [privileged_lo] elsewhere in this table, just kept
+ separately named so this block's own rows are self-contained and do not
+ depend on a binding declared for an unrelated purpose above. Given the
+ WORSE (higher) precedence int than [paul_companion_synth] would need to
+ win the day's one "other II class" slot on its own dignity ALONE -- the
+ whole point of the row below is that RG 110 does not care who wins that
+ contest; it adds Paul regardless. *)
+let lent_feria_synth = (cand ~origin:P.Temporal ~rank:V.Class3 "ef-lent-2-monday-synth", P.Privileged, 180)
+
let admit_cases =
[ (* RG 111 (§4): "I class: none save one privileged." *)
( "I-class day, only an ordinary commemoration due -> none admitted",
@@ -1109,7 +1136,46 @@ let admit_cases =
admitted",
lord_winner, lord_winner,
[ po sixtus P.Ordinary ],
- [ "pope-sixtus-ii-felicissimus-and-agapitus-martyrs" ] )
+ [ "pope-sixtus-ii-felicissimus-and-agapitus-martyrs" ] );
+ (* RG 110, shape (a)/(b): [chair-of-st-peter] observed, a competing
+ PRIVILEGED Lent feria also due for the day's single "other II class"
+ slot (RG 111(c) itself has no privilege-override clause -- unlike the
+ Sunday branch above -- so pure precedence order decides that slot on
+ its own, and [lent_feria_synth]'s own 180 beats
+ [paul_companion_synth]'s 999). Without RG 110, this is exactly
+ precedence_ef.ml's own measured defect (3,533 of 8,417 domain-wide
+ years, this task's own report): Paul loses the slot outright and is
+ never admitted at all. With RG 110, Paul is added ADDITIONALLY,
+ PREPENDED ahead of the feria per RG 110(c)'s own "ante omnes alias
+ commemorationes" -- both admitted, not one displacing the other. *)
+ ( "RG110 (a)/(b): chair-of-st-peter observed, Paul rides alongside a \
+ competing privileged Lent feria, uncapped and prepended",
+ chair_of_st_peter_synth, chair_of_st_peter_synth,
+ [ (paul_companion_synth, P.Ordinary, 999); lent_feria_synth ],
+ [ "paul"; "ef-lent-2-monday-synth" ] );
+ (* RG 110, shape (c): [chair-of-st-peter] itself LOSES the day outright
+ (observed is some unrelated II-class Sunday) but is admitted, on its
+ OWN Class2 dignity, as RG 111(b)'s single ordinary commemoration --
+ exactly the domain-wide 593-year pattern this task's own report
+ measures. RG 110(c)'s own text ("quoties vero oratio unius Apostoli
+ addenda est ad modum commemorationis...") governs precisely this: the
+ companion (Paul, Class3, no standing of its OWN for this Sunday's
+ rank-floored slot) rides along anyway, uncapped. *)
+ ( "RG110 (c): chair-of-st-peter admitted merely AS a commemoration \
+ (loses the day to an ordinary II-class Sunday), Paul still rides \
+ along",
+ cand ~rank:V.Class2 "ef-some-other-sunday", cand ~rank:V.Class2 "ef-some-other-sunday",
+ [ po chair_of_st_peter_synth P.Ordinary; (paul_companion_synth, P.Ordinary, 999) ],
+ [ "paul"; "chair-of-st-peter" ] );
+ (* Defensive: a trigger slug is [observed], but its companion is simply
+ not present among [comms] at all (a data gap, or -- as this exact
+ shape was for 30 June before this task's own [Add
+ commemoration-of-st-peter] directive -- an upstream omission).
+ {!PE.rg110_find_companion} must return [None] gracefully, not raise;
+ the day's own (empty, here) normal result is unaffected. *)
+ ( "RG110 defensive: chair-of-st-peter observed, no companion present in \
+ comms at all -> no crash, nothing added",
+ chair_of_st_peter_synth, chair_of_st_peter_synth, [], [] )
]
(* Order independence (brief: "the admitted set must not depend on input