diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-17 12:28:03 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-17 12:28:03 +0200 |
| commit | 8d1eb25a311e16ddb7bf89d2b21fb1ca0aa058a7 (patch) | |
| tree | 9c72d1c30f0f37ef7138325abb3ca26ebe68ff14 /test/test_differential.ml | |
| parent | 9947a28f3a40bd8ac36892dcf5aad59d9e6f847c (diff) | |
| download | colitur-8d1eb25a311e16ddb7bf89d2b21fb1ca0aa058a7.tar.gz colitur-8d1eb25a311e16ddb7bf89d2b21fb1ca0aa058a7.zip | |
test(oracle): compare reading citations against missalemeum
Layer 4 (test_oracle.ml) now extracts and compares the Epistle/Gospel
citation for every one of the 730 days in the 2026-2027 fixture, the
same axis Task 8 already added to layer 3. tools/
extract_missalemeum_oracle.py gained a structural citation-span
detector (the first "*...*"-wrapped span under 40 chars containing a
chapter:verse-shaped digit pair), verified exhaustively over all 1 458
Lectio/Evangelium sections. 728 of 730 days are comparable; the 2 that
are not (Good Friday, both years) have no such section in missalemeum's
own JSON at all -- a structural limit on the oracle's own side (M23),
not a colitur gap. 451 of 730 days differ and are all explained across
19 cited entries; 0 unexplained. Chain step 4 (the Commons) has no
layer-4 witness: confirmed empirically (a scratch sweep, not merely
re-asserted from Task 6's own report) that none of the 15 Commons/proper
saints is ever the observed office in this window.
The comparison surfaced three genuine colitur bugs in
data/ef/lectionary.sexp, all fixed at the source in
tools/bootstrap_lectionary.ml:
1. Holy Name of Jesus (ef-holy-name-sunday/ef-holy-name) carried a
mis-derived citation, borrowed by analogy from an unrelated ini
section ("ef-christmas-sunday-0", the Sunday-within-the-Octave's own
Mass) on the wrong assumption the two share a Mass. Disproved by
missalemeum's own extraction for both real Holy Name Sundays in its
window, confirmed against the Missal itself, twice, both scans
(Acts 4:8-12/Luke 2:21, not Gal 4:1-7/Luke 2:33-40).
2. RG 17(a)'s own "diebus ferialibus" rubric (immediately following the
Holy Name heading, both scans) was never implemented: 2-5 January
ferias repeat 1 January's Mass, 7-12 January ferias before Holy
Family Sunday repeat Epiphany's, and Holy Family's own week has a
named formula ("Missa Dominicae Primae post Epiphaniam"). All three
fell to step 3's undifferentiated Sunday walkback instead. Fixed for
three 5-weekday families, deliberately excluding Saturday from all
three -- RG 78's BVM Saturday Office wins there unconditionally,
confirmed against missalemeum's own title on this window's own such
Saturdays.
3. Corpus Christi and Sacred Heart (both real, never-impeded I-class
movable feasts) had no lectionary entry at all. Both engines
independently fell back to Trinity Sunday's own citation and
silently agreed on the wrong answer -- the "Holy Thursday violet in
both" shape CLAUDE.md names for exactly this reason.
Because lectionary.sexp is shared with layer 3 (the lectio differential,
2005-2050), these fixes changed colitur's output for the whole domain,
not only 2026-2027. data/ef/expected-divergences.sexp and
test_differential.ml needed matching updates: C1 narrowed 361->173 and
C25 narrowed 57->13 (rows that now resolve correctly moved to new
entries), C16's note corrected (count unchanged), and six new entries
added (C29-C34, 397 rows total, all verdict colitur). test_lectionary.ml
and test_lectionary_ef.ml's own pins were updated to match (entry count
131->148; one step-3 regression test re-pointed to a date that still
genuinely exercises that step).
One entry, M26 (30 rows, verdict open), is a genuine unfixed gap: colitur's
step-3 "resume the preceding Sunday" fallback is its only ferial-Mass
mechanism, and missalemeum's own selection is more granular in three
confirmed ways (a rotating votive Mass of the BVM, a named weekly
formula for at least one week, and later Time-after-Pentecost weeks this
task's own investigation did not narrow to a single rule) -- the same
"needs a season-keyed selection mechanism, new behaviour not new data"
shape data/ef/expected-divergences.sexp's own C6/C25 and Task 6's own
residual concern already name, out of this task's own scope to build.
dune test: 358 tests green. COLITUR_EXHAUSTIVE_SWEEP=1 dune test
--force: 359 tests green, 89.5s.
Diffstat (limited to 'test/test_differential.ml')
| -rw-r--r-- | test/test_differential.ml | 158 |
1 files changed, 154 insertions, 4 deletions
diff --git a/test/test_differential.ml b/test/test_differential.ml index 655a054..a89b17b 100644 --- a/test/test_differential.ml +++ b/test/test_differential.ml @@ -699,6 +699,57 @@ let epiphany_week_shift_years_2005_2050 = [ 2008; 2013; 2019; 2030; 2036; 2041; let year_of_date date = int_of_string (String.sub date 0 4) +(* C29-C34 -- Task 9 (branch ef-lectionary, layer-4 oracle): six colitur-side + citation fixes, all found via the SAME mechanism -- missalemeum (test/ + test_oracle.ml, 2026-2027) disagreeing with colitur's OLD step-3 + fallback/absent-entry answer, traced to an explicit primary-source + citation each time (tools/bootstrap_lectionary.ml's own + [holy_name_entries]/[epiphanytide_opening_entries]/ + [movable_feast_entries] carry the full scan citations, not repeated + here). lectio has no equivalent data for any of the six (its own ini + either has no entry, matching colitur's OWN prior gap for + [ef-corpus-christi]/[ef-sacred-heart], or the SAME mis-borrowed value + colitur used to carry for the January families before this task's own + fix, see [colitur_keys]'s own CORRECTED note in that generator) -- so + every occurrence across the WHOLE 2005-2050 differential window newly + diverges, not only the 2026-2027 oracle window that found it. Each is + its own id, not folded into a neighbour, per this file's own standing + discipline (C14/C15/C16 above): a slug family's own citation fix is a + distinct fact from another family's, even where the underlying task + and citation shape are similar. *) +let holy_name_sunday_slug = "ef-holy-name-sunday" + +let christmas_1_weekday_slugs = + List.map (fun wd -> "ef-christmas-1-" ^ wd) [ "monday"; "tuesday"; "wednesday"; "thursday"; "friday" ] + +let christmas_2_weekday_slugs = + List.map (fun wd -> "ef-christmas-2-" ^ wd) [ "monday"; "tuesday"; "wednesday"; "thursday"; "friday" ] + +let time_after_epiphany_1_weekday_slugs = + List.map + (fun wd -> "ef-time-after-epiphany-1-" ^ wd) + [ "monday"; "tuesday"; "wednesday"; "thursday"; "friday" ] + +(* C31/C32's OWN Saturday ripple, checked for and confirmed real, not + theorised: [ef-christmas-1-saturday] and [ef-time-after-epiphany-1- + saturday]/[ef-christmas-2-saturday] deliberately have NO direct entry + (RG 78's BVM Saturday Office, above) -- but a Saturday still falls + through to step 3's OWN preceding-Sunday walkback, and on the (large + minority of) years where that walk lands on [ef-holy-name-sunday] + specifically, it now inherits THAT slug's newly-corrected citation as + a side effect, with no direct entry of its own involved at all. + [ef-christmas-1-saturday]'s own walkback structurally can never reach + that far forward (it only ever lands in December, C25's own unchanged + population, confirmed by the pinned test_lectionary_ef.ml case) -- + only the OTHER two families' Saturdays are affected, so only they need + the wider slug list; a Saturday whose value is genuinely unaffected + this year simply produces no row needing an id at all ([diffs = []]), + not a false positive. *) +let christmas_2_weekday_slugs_with_saturday = christmas_2_weekday_slugs @ [ "ef-christmas-2-saturday" ] + +let time_after_epiphany_1_weekday_slugs_with_saturday = + time_after_epiphany_1_weekday_slugs @ [ "ef-time-after-epiphany-1-saturday" ] + (* C20 (task 8): lectio genuinely computes NO reading at all -- "-"/"-" on both parts -- for 14 civil days across 2005-2050, all seven of the readingless class-3 saints Task 6 gave a proper or a Common @@ -950,10 +1001,28 @@ let september_ember_sat_slug = "ef-september-ember-sat" respectively" (the right four numbers, the wrong weekday each was attached to). Re-measured directly against the real resolver: Wednesday 6, Thursday 19, Friday 19, Saturday 13 (6 + 19 + 19 + 13 = - 57, no residue). *) -let rg69_one_hop_slugs = - [ "ef-christmas-1-wednesday"; "ef-christmas-1-thursday"; "ef-christmas-1-friday"; - "ef-christmas-1-saturday" ] + 57, no residue). + + NARROWED, Task 9 (branch ef-lectionary, layer-4 oracle): three of the + four weekdays (Wednesday/Thursday/Friday) now have their OWN direct + lectionary entry (tools/bootstrap_lectionary.ml's own + [epiphanytide_opening_entries], RG 17(a)'s "diebus ferialibus a 2 ad 5 + ianuarii Missa dicitur ut die 1 ianuarii", both scans) -- they no + longer reach step 3's one-hop walkback THIS entry's own citation + describes at all, so keeping them here would misdescribe what + actually happens on those three weekdays now. See [C30] below for + their own (DIFFERENT, larger) new population -- colitur is RIGHT + there, not merely differently wrong, so it is a separate id with its + own [verdict colitur], not a re-adjudication of this one. Only + [ef-christmas-1-saturday] remains here: deliberately NOT given a + direct entry (RG 78's BVM Saturday Office wins that day + unconditionally whenever nothing else does, {!Rite_ef.Temporal_ef}'s + own [bvm_saturday_names] -- giving it the "repeat 1 January" citation + would be wrong on exactly the days this entry's own citation already + describes as correct for the OTHER four weekdays), so this ONE + weekday's own step-3 walkback -- and this entry's own citation, + "Tit. 3, 4-7" -- is genuinely unchanged by this task. *) +let rg69_one_hop_slugs = [ "ef-christmas-1-saturday" ] (* [layer_c_reason l c diffs] returns the [data/ef/expected-divergences.sexp] [id] this row-pair's remaining (post Layer A/B) diff set belongs to, or @@ -1046,6 +1115,48 @@ let layer_c_reason (l : row) (c : row) diffs = && subset diffs [ Slug_f; Rank; First_f; Gospel_f ] && String.equal c.slug "ef-holy-name" then Some "C16" + else if + (* C29 -- Task 9: the Holy-Name-SUNDAY shape (RG 17(a)'s own primary + Sunday case, distinct from C16's fallback above) -- Season/Slug_f + already agree (Layer A already normalises lectio's own + "ef-christmas-sunday-0" for this civil date onto colitur's + "ef-holy-name-sunday", the SAME alias this generator's OWN + [colitur_keys] used to (wrongly) borrow a citation through -- + Layer A's alias and the generator's OLD citation-sourcing bug were + two separate uses of the same underlying fact, only one of which + was ever wrong), so only the citation itself is new. *) + diffs = [ First_f; Gospel_f ] && String.equal c.slug holy_name_sunday_slug + then Some "C29" + else if + (* C30 -- Task 9: RG 17(a)'s own "diebus ferialibus a 2 ad 5 ianuarii" + rubric, the five non-Saturday weekdays (Saturday stays C25's own, + narrowed note above explains why). *) + diffs = [ First_f; Gospel_f ] && List.mem c.slug christmas_1_weekday_slugs + then Some "C30" + else if + (* C31 -- Task 9: the SAME rubric's own next sentence, "diebus + ferialibus a 7 ad 12 ianuarii ante dominicam I post Epiphaniam... + Missa de festo Epiphaniae". A SUBSET guard, not an exact match, + unlike C29/C30 -- this slug family's own civil dates ALREADY + carried a Season/Slug_f/Colour_f divergence before this task + (lectio's own season boundary starts Time-after-Epiphany at + Epiphany itself, RG 72-73's own later boundary colitur keeps; + lectio's own week numbering has no Holy Family to wait for, so its + own slug for these dates is already "ef-time-after-epiphany-1- + <weekday>", not "ef-christmas-2-..."), previously absorbed by C1's + own [jan_6_13_slug] allow-list (which already names this family). + First_f/Gospel_f now join an EXISTING divergence, they do not + create a new, cleaner one -- ONE of the two, not necessarily both: + a feria's Epistle and Gospel are independent lookups, and can each + happen to already coincide (e.g. the Gospel pericope shared with a + neighbouring office while the Epistle differs). [_with_saturday] + -- see that list's own comment for why Saturday belongs here for + THIS family (a step-3 ripple through the now-corrected + [ef-holy-name-sunday], not a direct entry of its own). *) + subset diffs [ Season; Slug_f; Colour_f; First_f; Gospel_f ] + && (List.mem First_f diffs || List.mem Gospel_f diffs) + && List.mem c.slug christmas_2_weekday_slugs_with_saturday + then Some "C31" else if is_bvm_saturday_row c diffs then Some "C17" else if diffs = [ Colour_f ] && List.mem c.slug audit_colour_corrected_slugs then Some "C18" else if @@ -1054,6 +1165,45 @@ let layer_c_reason (l : row) (c : row) diffs = && subset diffs [ Colour_f; First_f; Gospel_f ] then Some "C19" else if + (* C32 -- Task 9: "Missa Dominicae Primae post Epiphaniam", Holy + Family's own week, the five non-Saturday weekdays. Checked AFTER + C19 deliberately: C19's own 7 "week shift" years already explain + this same slug family's own citation divergence there (a + DIFFERENT root cause, the week-numbering offset, not this task's + own fix) -- this entry must not re-claim those rows under a + citation-content reason C19 already owns, so its own population is + exactly the OTHER (non-shift-year) civil dates. A SUBSET guard, + the same reason as C31 immediately above: unlike C29/C30, THIS + slug family's own civil dates already carried a bare + Season/Colour_f divergence before this task (SAME slug on both + sides here, unlike C31 -- lectio's own season boundary alone, + RG 72-73 vs Epiphany), previously absorbed by C1's own generic + 6-13 January window (no [Slug_f] involved, so C1's own + [jan_6_13_slug] gate was never even reached). First_f/Gospel_f now + join that existing divergence -- ONE of the two, the same reason + as C31's own note. [_with_saturday]: this family's own Saturday IS + reachable by a step-3 walk landing on [ef-holy-name-sunday] + (unlike [ef-christmas-1-saturday]'s own walk, which structurally + cannot reach that far forward -- confirmed, not assumed, by the + pinned test_lectionary_ef.ml case for that one slug). *) + subset diffs [ Season; Colour_f; First_f; Gospel_f ] + && (List.mem First_f diffs || List.mem Gospel_f diffs) + && List.mem c.slug time_after_epiphany_1_weekday_slugs_with_saturday + then Some "C32" + else if + (* C33/C34 -- Task 9: two major movable feasts of the Lord that had NO + lectionary entry at all before this task (tools/ + bootstrap_lectionary.ml's own [movable_feast_entries]) -- lectio has + none either, so colitur and lectio used to independently fall back + to the SAME preceding-Sunday (Trinity's own) citation and silently + agree on the wrong answer, the "Holy Thursday violet in both" shape + CLAUDE.md's own validation-layers section names. Two ids, not one: + distinct feasts, distinct citations, the same discipline C33/C34's + neighbours already apply. *) + diffs = [ First_f; Gospel_f ] && String.equal c.slug "ef-corpus-christi" + then Some "C33" + else if diffs = [ First_f; Gospel_f ] && String.equal c.slug "ef-sacred-heart" then Some "C34" + else if diffs = [ First_f; Gospel_f ] && String.equal l.first "-" && String.equal l.gospel "-" && List.mem c.slug lectio_no_reading_slugs then Some "C20" |
