diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/test_oracle.ml | 121 |
1 files changed, 114 insertions, 7 deletions
diff --git a/test/test_oracle.ml b/test/test_oracle.ml index ae82b31..df56bcc 100644 --- a/test/test_oracle.ml +++ b/test/test_oracle.ml @@ -1805,6 +1805,12 @@ let norm_citation s = let m21_2038_slugs = m21_colour_slugs let classify_2038 (c : colitur_row) (o : oracle_row) diffs = + let has_comm slug = List.exists (fun (s, _, _, _) -> s = slug) c.c_commemorations in + let has_comm_prefix p = + List.exists + (fun (s, _, _, _) -> String.length s >= String.length p && String.sub s 0 (String.length p) = p) + c.c_commemorations + in let title = o.o_title in let contains hay needle = let nh = String.length needle and lh = String.length hay in @@ -1839,12 +1845,106 @@ let classify_2038 (c : colitur_row) (o : oracle_row) diffs = 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)" + (* ---- commemoration classes (2026-08-18) ------------------------------ + Every one below is an already-cited family from the 2026-2027 + allow-list, re-appearing in a live window now that these compare + commemorations. None is a new adjudication; each points at the entry + that decided it. *) + else if has_comm "commemoration-of-the-seven-sorrows" || has_comm "major-litanies" then + (* Same entity, different English name form: colitur's own resolved name + ("The Seven Sorrows of the Blessed Virgin Mary", "The Major Litanies") + against missalemeum's ("For Our Lady of the Seven Sorrows", "Pro + rogationibus"). Both streams commemorate the SAME thing. Counted as a + divergence because the comparator matches on name text, which is the + only identity signal available -- not because the calendars differ. *) + Some "COMM-NAME-FORM (same entity, different English name)" + else if has_comm "commemoration-of-st-peter" then + Some "PETER-COMPANION-ABSENT-UPSTREAM (M19)" + else if has_comm "barbara" then Some "BARBARA-ABSENT-UPSTREAM (M22)" + else if has_comm_prefix "ef-advent-" then Some "ADVENT-FERIA-COMM (M10)" + else if + List.mem Comm_presence diffs && c.c_commemorations = [] + && String.length c.c_observed_slug > 3 + then Some "NATIVITY-OCTAVE-COMM-MISSING (M11, colitur's own gap, verdict open)" + (* THE ONE GENUINELY NEW FINDING of this extension, and it is not a naming + artefact. 2038-06-02: the Ascension Vigil (II class) admits ONE + commemoration under RG 111(c), and TWO candidates compete -- + `rogation-wednesday` and `sts-marcellinus-peter-erasmus`. BOTH are + Commemoration_only, so neither has a row in RG 91's table and [band] + returns [unclassified] for both; RG 113's "servetur ordo tabellae + praecedentiae" has nothing to order by, and [admit] falls through to its + alphabetical slug tie-break, which picks the Rogation. missalemeum picks + the saints. + + This is the tie-break CLAUDE.md records as "only ever exercised between + two Commemoration_only candidates, neither of which has any RG 91 table + position" -- and this is its FIRST live, externally-witnessed instance. + The decision is currently made by slug alphabet, which is arbitrary and + not rubrical. + + There may be a real rule: RG 113's own FIRST sentence is "Commemoratio de + Tempore fit primo loco", and a Rogation is arguably de Tempore, which + would make colitur right for a reason it is not currently using. That + turns on whether the entry should carry subject Temporal rather than the + Saint it inherited from the Major Litanies precedent -- a question the + movable-date-specs spec explicitly deferred as "behaviourally inert", + which it no longer is. NOT decided here: recorded, cited, and left for a + dedicated task rather than settled by whichever answer happens to match + the oracle. *) + else if has_comm "rogation-wednesday" then + Some "COMM-ONLY-TIE-BREAK (alphabetical, arbitrary -- see register 6.16)" + (* The documented comparator LIMIT, not a calendar disagreement: colitur + resolves a commemoration's identity through its own English name, and a + TEMPORAL-origin commemoration (an impeded feria, an Ember or Rogation + day) has none -- Temporal_ef never sets one. M15 carries the same shape + in the 2026-2027 window. Counted and named rather than skipped, so the + population is visible instead of silently passing. *) + (* M8's own shape: a fixed I-class feast landing on an ordinary Sunday. RG + 109(a) makes "of a Sunday" always privileged and RG 111(a) admits exactly + one privileged commemoration on a I-class day, so the impeded Sunday IS + that one. missalemeum shows no commemoration at all. M8 names All Saints + and the Assumption in the 2026-2027 window; this is the same rule + reaching a different feast. *) + else if has_comm_prefix "ef-" && List.mem Comm_presence diffs && c.c_rank = 1 then + Some "IMPEDED-SUNDAY-COMM (M8's rule, RG 109(a)/111(a))" + else if List.mem Comm_identity_unresolved diffs then + Some "COMM-IDENTITY-UNRESOLVED (temporal-origin, no English name -- M15's limit)" else None +(* COMMEMORATIONS join the live-window comparison (2026-08-18). + + Until now the live windows compared rank, colour and the two citations + only, and commemorations were checked against an oracle in the 2026-2027 + fixture alone -- 227 days out of the ~968 000 commemoration-bearing days in + the domain, about 0.02%. That was by some distance the thinnest axis in the + project, and the reason is worth restating: layer 3 (16 801 days) compares + NO commemorations at all and never can, because lectio's own trailing + "+slug" tokens are its LOSING candidates rather than an RG 111 admitted + set, so the largest evidence source is structurally silent here. Roughly a + third of all days carry at least one commemoration, and `admit` is the most + intricate code in the engine, so the gap mattered. + + Presence, count and IDENTITY are compared, reusing [identity_diff] -- + the same function the 2026-2027 comparator uses, with the same limits: it + resolves a SANCTORAL-origin commemoration by colitur's own English name and + returns [Comm_identity_unresolved] for a temporal-origin one, which carries + no name to match. Unresolved is a counted, classified outcome, never a + silent pass. + + OBSERVED-identity is deliberately still NOT compared in the live windows. + That axis is a separate, already-understood limit (M18's own shape: a + temporal-origin observed day has no English name either), and folding it in + here would flood these windows with a divergence class that says nothing + about commemorations. *) let diffs_2038 (c : colitur_row) (o : oracle_row) = let d = ref [] in if c.c_rank <> o.o_rank then d := Rank :: !d; if not (List.mem c.c_colour o.o_colours) then d := Colour_f :: !d; + let c_has = c.c_commemorations <> [] and o_has = o.o_commemorations <> [] in + if c_has <> o_has then d := Comm_presence :: !d; + if c_has && o_has && List.length c.c_commemorations <> List.length o.o_commemorations then + d := Comm_count :: !d; + (match identity_diff c o with Some f -> d := f :: !d | None -> ()); (match (c.c_first, o.o_first) with | Some a, Some b when norm_citation a <> norm_citation b -> d := First_mismatch :: !d | _ -> ()); @@ -1923,13 +2023,20 @@ let test_2038_class_counts () = those 13 days no longer differ at all. An id with no rows must not be declared -- the count assertion rejects an unused one, which is what keeps this list honest. *) - [ ("CHRIST-THE-KING-WEEK (M26 shape 2b)", 2); - ("CHRISTMAS-MULTI-MASS (M27)", 1); - ("COLOUR (M21)", 7); - ("JUDITH (M28, register 6.6)", 2); - ("MISSAL-TWO-PART-CITATION (register 6.9)", 1); - ("PERPETUA-COMMON (register 6.8)", 1) - ] + [ ("ADVENT-FERIA-COMM (M10)", 10); + ("BARBARA-ABSENT-UPSTREAM (M22)", 1); + ("CHRIST-THE-KING-WEEK (M26 shape 2b)", 2); + ("CHRISTMAS-MULTI-MASS (M27)", 1); + ("COLOUR (M21)", 7); + ("COMM-NAME-FORM (same entity, different English name)", 2); + ("COMM-ONLY-TIE-BREAK (alphabetical, arbitrary -- see register 6.16)", 1); + ("JOSEPH-ANNUNCIATION-TRANSFER-ORDER (C14's own collision)", 2); + ("JUDITH (M28, register 6.6)", 2); + ("MISSAL-TWO-PART-CITATION (register 6.9)", 1); + ("NATIVITY-OCTAVE-COMM-MISSING (M11, colitur's own gap, verdict open)", 2); + ("PERPETUA-COMMON (register 6.8)", 1); + ("PETER-COMPANION-ABSENT-UPSTREAM (M19)", 1) + ] |> List.sort compare in Alcotest.(check (list (pair string int))) "2038 divergence classes and their counts" expected actual |
