summaryrefslogtreecommitdiff
path: root/test/test_oracle.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-17 14:13:02 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-17 14:13:02 +0200
commit3565ebd1608a7d87e0d890f9953845efcfe743ca (patch)
tree6b2d056475b4f36d041e3ef1522ca7c7c11110ec /test/test_oracle.ml
parent5d236c75c557a7e9ed4a8a852b8089aca48b594e (diff)
downloadcolitur-3565ebd1608a7d87e0d890f9953845efcfe743ca.tar.gz
colitur-3565ebd1608a7d87e0d890f9953845efcfe743ca.zip
fix(lectionary): two Judith citations wrong in both engines
A live-missalemeum sweep over a full liturgical year (2028, 364 days) returned 333 matching and 31 differing days: 17 already-known or pure notation, 3 new. All three now adjudicated against the photographic scans of the 1962 Missal. The Assumption's Epistle reads "Iudith 13, 22-25; 15, 10" (scan1:35357). Both engines carried "Judith 13:22-25; 13:15; 13:10" -- a chapter carry-over defect that re-applied chapter 13 to the second citation and so invented two verses the Missal never cites. The Seven Sorrows reads "Iudith 13, 22 et 23-25" (scan1:36938, corroborated at 28468); both carried "Judith 13:22; 13:25", dropping the range. The third, St Monica, resolves the other way: the Missal gives 1 Timothy (scan2:32679, heading and incipit both legible; scan1:29524 agrees) where missalemeum serves the Common of Holy Women's Proverbs -- colitur is right, no change. Layer 3 could not have found either citation defect. colitur's data is bootstrapped from lectio, and lectio is the other side of that differential, so while both engines produced the identical wrong answer the comparison held it against itself and reported agreement -- the shared-lineage blindness CLAUDE.md names, now with a second live witness beside Holy Thursday's colour. Only an external oracle could see it, and only outside the committed fixture's own window. Fixed upstream in lectio, re-bootstrapped here (provenance SHA-256 moved to 54f6bfc5, verified against the source), fixture regenerated. The upstream fix inverted layer 3 from blind to load-bearing here: reverting the Assumption citation now reddens both layers, where before it would have reddened neither. Verified by mutation, both directions. Allow-lists: - C22 closed and removed (128 rows -> 0), not re-adjudicated -- the other engine was fixed to agree, the same shape as the C2-C5/C7/C9-C13/C21 closures. Its own note had already flagged the Lenten Ember dead-key bug for upstream; lectio now also fails its build on any unreachable lectionary key rather than serving a plausible wrong Mass. - M28 opened (3 rows, verdict colitur), pinning both sides' citation text rather than the date and diff shape alone, so a different divergence landing on the same date cannot be swallowed. - M8's gate widened, expected_rows unchanged at 2: 2027-08-15 carries both its cause and M28's, and one entry is admitted per day. It stays under M8, which now requires its own commemoration difference to be present and admits the citation difference only when it satisfies M28's two-sided predicate. Neither cause absorbs the other. layer_m_reason's oracle-row parameter, kept named since M2 closed for exactly such a future reader, is live again. Register: docs/research/rules-register.md section 6.6.
Diffstat (limited to 'test/test_oracle.ml')
-rw-r--r--test/test_oracle.ml74
1 files changed, 67 insertions, 7 deletions
diff --git a/test/test_oracle.ml b/test/test_oracle.ml
index 1ad4b1f..1e724b8 100644
--- a/test/test_oracle.ml
+++ b/test/test_oracle.ml
@@ -802,6 +802,50 @@ let m20_commemoration_matches (c : colitur_row) =
colitur. *)
let m8_dates = [ "2026-11-01"; "2027-08-15" ]
+(* M28 -- the 1962 Missal's own two Judith citations, primary-source-verified
+ against the photographic scans this task (branch ef-lectionary) read
+ directly, after a live-missalemeum full-year sweep surfaced them:
+
+ Assumption (15 Aug) scan1:35357, under "IN ASSUMPTIONE BEATAE
+ MARIAE VIRGINIS" -- "Iudith 13, 22-25; 15, 10"
+ Seven Sorrows (15 Sep) scan1:36938, corroborated independently at
+ scan1:28468 -- "Iudith 13, 22 et 23-25"
+
+ Both engines used to carry a chapter-carry-over defect here: lectio's own
+ generator emitted "Judith 13:22-25; 13:15; 13:10" for the Assumption
+ (inventing two verses out of the second citation's own "15, 10" by
+ re-applying chapter 13) and "Judith 13:22; 13:25" for the Seven Sorrows
+ (dropping the "et 23-" range). colitur inherited both through its own
+ bootstrap -- the "Holy Thursday was violet in both" shared-lineage shape
+ this project's own CLAUDE.md names, and the reason layer 3 could never
+ have found this: lectio IS the other side of that comparison. Fixed
+ upstream in lectio (v0.46.1+) and re-bootstrapped here; missalemeum
+ still serves the defective form, so the divergence is now visible on
+ layer 4 and adjudicated colitur.
+
+ The predicate pins BOTH sides literally, not merely the diff shape -- the
+ C6/C14 failure mode this file's own header documents (a date-and-shape
+ gate that would silently swallow a DIFFERENT citation divergence landing
+ on the same date). It is also the first reader of [layer_m_reason]'s own
+ oracle-row parameter since M2 closed; that parameter was deliberately
+ kept named and typed for exactly this ("so a FUTURE oracle-title
+ predicate has somewhere to plug back in without a signature change"). *)
+let judith_divergence (c : colitur_row) (o : oracle_row) =
+ match (c.c_first, o.o_first) with
+ (* Assumption *)
+ | Some "Judith 13:22-25; 15:10", Some "Judith 13:22-25; 13:15; 13:10" -> true
+ (* Seven Sorrows *)
+ | Some "Judith 13:22; 13:23-25", Some "Judith 13:22; 13:25" -> true
+ | _ -> false
+
+(* 2027-08-15 is deliberately ABSENT here: it carries this divergence AND
+ M8's own, independently-caused one (the Assumption falls on a Sunday that
+ year), and the classifier admits one entry per day. It is accounted under
+ M8, whose own gate names this predicate explicitly rather than widening
+ to [First_mismatch] blindly -- neither cause is silently absorbed into
+ the other, the same discipline C15's own split from C1 already set. *)
+let m28_dates = [ "2026-08-15"; "2026-09-15"; "2027-09-15" ]
+
(* M9 -- REMOVED, ef-rebootstrap (2026-08-12): see data/ef/expected-
divergences-missalemeum.sexp's own "FIVE MORE REMOVED" note. St
Theodore (9 Nov) is now present in data/ef/sanctoral.sexp (theodore),
@@ -1277,12 +1321,14 @@ let m26_dates =
citation fields are not, discovered by this task). *)
let m27_dates = [ "2026-12-25"; "2027-12-25" ]
-(* [_o] (the oracle's own row) is unused now that M2 -- its one reader, via
- [o.o_title] -- is closed/removed (see the comment above [m1_dates]):
- every remaining predicate below reads only [c]/[diffs]. Kept as a named,
- typed parameter (not dropped from the signature) so a FUTURE oracle-title
- predicate has somewhere to plug back in without a signature change. *)
-let layer_m_reason (c : colitur_row) (_o : oracle_row) diffs =
+(* The oracle's own row went unused when M2 -- its one reader, via
+ [o.o_title] -- was closed/removed (see the comment above [m1_dates]), and
+ was kept as a named, typed parameter rather than dropped from the
+ signature "so a FUTURE oracle-title predicate has somewhere to plug back
+ in without a signature change". Task 9 (branch ef-lectionary) is that
+ future: {!judith_divergence} pins the ORACLE's own citation as well as
+ colitur's, so the parameter is live again and no longer underscored. *)
+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
dates is TEMPORAL-origin (the Sunday itself, RG33's own point -- the
@@ -1312,7 +1358,21 @@ let layer_m_reason (c : colitur_row) (_o : oracle_row) diffs =
Some "M3"
else if List.mem c.c_date m5_dates && diffs = [ Comm_identity_mismatch ] && m5_commemoration_matches c then
Some "M5"
- else if List.mem c.c_date m8_dates && diffs = [ Comm_presence ] then Some "M8"
+ (* M8's own gate widened, Task 9 fix (branch ef-lectionary): 2027-08-15 is
+ BOTH an impeded-Sunday day (M8's own cause) and a Judith-citation day
+ (M28's), and the classifier admits one entry per day. [Comm_presence]
+ stays REQUIRED -- M8's own divergence must actually be present, so this
+ can never degrade into a bare citation gate -- and [First_mismatch] is
+ admitted only when it is exactly the M28 shape, both sides pinned. A
+ citation divergence of any OTHER shape, on either M8 date, still
+ escapes to unexplained. *)
+ else if
+ List.mem c.c_date m8_dates
+ && subset diffs [ Comm_presence; First_mismatch ]
+ && List.mem Comm_presence diffs
+ && ((not (List.mem First_mismatch diffs)) || judith_divergence c o)
+ then Some "M8"
+ else if List.mem c.c_date m28_dates && diffs = [ First_mismatch ] && judith_divergence c o then Some "M28"
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"
(* M13's own subset widened AGAIN (this task, following the SAME pattern