diff options
Diffstat (limited to 'test/test_differential.ml')
| -rw-r--r-- | test/test_differential.ml | 196 |
1 files changed, 89 insertions, 107 deletions
diff --git a/test/test_differential.ml b/test/test_differential.ml index 4d6aab0..62c7a48 100644 --- a/test/test_differential.ml +++ b/test/test_differential.ml @@ -51,9 +51,20 @@ *** THE THREE-LAYER DESIGN (controller ruling, Task 15 dispatch) *** - Of 16801 day-pairs (2005-2050), 11206 already match on the seven columns. - Of the 5595 that don't, exactly 25 distinct (field-diff) signatures cover - all of them (task-15-class-summary.txt). They resolve into three strictly + REFRESHED (2026-08-12, task 2026-08-12-colitur-rg16a, branch ef-rebootstrap): + the fixture was regenerated from lectio's CURRENT HEAD (3b32c00), which has + fixed seven EF calendar defects since the fixture was first pinned (commit + 2386a45) -- see the fixture's own provenance note for the exact commits and + defect list. Of 16801 day-pairs (2005-2050), 11826 now already match on the + raw seven columns (up from roughly 11201 against the stale fixture); of the + 4975 that don't, only 10 distinct RAW (field-diff, including the + never-compared week column) signatures cover all of them, independently + recomputed against this fixture and colitur's current output, not copied + from the original task-15-class-summary.txt (which described the OLD + fixture and is stale). After Layers A and B below strip the week column and + the vocabulary/numbering artifacts, only 540 of those 4975 remain genuine + differences -- all 540 explained by Layer C (368 + 138 + 31 + 3, see each + entry's own citation), 0 unexplained. They resolve into three strictly separate layers: - Layer A (this file's [norm_season]/[norm_slug]): vocabulary. A @@ -67,7 +78,7 @@ done even where it would shorten the table. - Layer B ([strip_epiphany_index]): numbering. The ONE case in the whole - 5595 where a slug's embedded index genuinely cannot be reconciled by a + 4975 where a slug's embedded index genuinely cannot be reconciled by a literal table (Time-after-Epiphany's non-constant offset, limit 3 above) -- both sides' embedded week digit is stripped to a common family+weekday form before comparing, while rank and colour (which @@ -76,37 +87,48 @@ family would still be caught by everything except the digit itself. - Layer C (data/ef/expected-divergences.sexp, matched by - [layer_c_reason] below): the CITED allow-list. Eleven genuine liturgical - disagreements (C11 added by Task 16's oracle work, below), each citing - its RG paragraph and stating which engine is right (always colitur, - verified against the Missal/register, never against lectio's own - behaviour -- "lectio does it differently" is not itself a justification - anywhere in this file). This is the ONLY layer that may cover a - difference in rank, colour, or which celebration is observed; A and B - never do (enforced structurally below: A/B only ever - touch the season/slug fields, and Layer C's predicates each require an - exact, narrow field-diff SET, not "anything goes"). + [layer_c_reason] below): the CITED allow-list. Each entry cites its RG + paragraph and states which engine is right (always colitur, verified + against the Missal/register, never against lectio's own behaviour -- + "lectio does it differently" is not itself a justification anywhere in + this file). This is the ONLY layer that may cover a difference in rank, + colour, or which celebration is observed; A and B never do (enforced + structurally below: A/B only ever touch the season/slug fields, and + Layer C's predicates each require an exact, narrow field-diff SET, not + "anything goes"). - 13 January (register §6's long-open "Baptism of the Lord" item) is - EMPIRICALLY CONFIRMED FIXED, not separately allow-listed, ONLY in the 39 - of 46 years it is NOT a Sunday: colitur's slug/rank/colour equal - lectio's fixture exactly there (the sanctoral wiring landed in Task 11's - "13 Jan now resolves to the Baptism of the Lord" review note), and the - only residual difference on those 39 rows is season (covered by Layer - C's C1, the Jan 6-13 boundary). + REFRESHED (2026-08-12, ef-rebootstrap fixture regeneration): lectio's own + fix wave (2386a45 -> 3b32c00, provenance note has the full commit list) + independently fixed the exact defects nine of the thirteen entries this + file used to carry were about -- C2, C3, C4, C5, C7, C10, C11, C12 and C13 + all now match ZERO rows against the refreshed fixture and were CLOSED + (removed from data/ef/expected-divergences.sexp and from + [layer_c_reason] below), each with its citation preserved and the closure + recorded in docs/research/rules-register.md, not silently deleted -- see + the report for the full before/after account. C9's old shape ("St Joseph + observed ON a Lent Sunday", lectio's own defect 4) also closed the same + way, but a NARROWER, different divergence involving the same saint + survived the refresh and was re-cited as a new entry, C14 (below), not + folded back into the old C9 id (the two are different rules; conflating + them would be exactly the "count proving cardinality where identity was + required" vacuity flavour this project's harnesses are specifically + checked against). Three entries survive unchanged in kind: C1 (368 rows, + up from 361 -- the 7 rows C13 used to carve out fold back into C1's own + shape now that lectio's slug matches there too, see C1's own note), C6 + (138 rows, unchanged count but a narrower shape -- lectio fixed the RANK + this entry used to also cover, leaving only the SLUG naming difference, + see C6's own note) and C8 (31 rows, wholly unchanged -- lectio still + computes no Rogation days at all). - CORRECTED (ef-rebootstrap fix round 1, F2): this note previously said - "in all 46 years" and "the only residual difference is season" without - qualification -- WRONG once `commemoration-of-the-baptism-of-the-lord` - became `subject = Lord` (ef-rebootstrap): on the remaining 7 years (13 - January itself falls on a Sunday: 2008, 2013, 2019, 2030, 2036, 2041, - 2047), RG16(a) now makes colitur observe the Baptism itself where it - used to observe the Sunday -- the OBSERVED SLUG differs from lectio's - fixture too, not merely colour. Allow-listed separately as C13 - (`data/ef/expected-divergences.sexp`), whose own note has the full - account, including a live cross-check against lectio's CURRENT engine - (not the committed fixture, which predates lectio's own equivalent - fix) -- see the report. *) + 13 January (register §6's long-open "Baptism of the Lord" item) is + EMPIRICALLY CONFIRMED FIXED, not separately allow-listed, in ALL 46 years + again as of this refresh: lectio's own fix wave independently fixed its + equivalent of the same RG16(a) defect the now-closed C13 used to allow- + list (its slug now matches colitur's `commemoration-of-the-baptism-of- + the-lord` on all 7 of the Sunday years too, not only the 39 non-Sunday + ones), so the residual difference on every one of the 46 rows is season + alone -- covered by C1, the Jan 6-13 boundary, with no separate entry + needed any more. *) module Cal = Colitur_kernel.Calendar module Layer = Colitur_kernel.Layer @@ -136,7 +158,7 @@ let allow_list_path = "../data/ef/expected-divergences.sexp" deliberately, after re-running the exact command the provenance note names -- never by copying the actual value back in to make a mismatch pass, which would defeat the point of pinning it at all. *) -let fixture_sha256 = "2ca3eeeda4e7a0406c4d004c1b2003fc0df671aca9af18a1b506543a721c8bac" +let fixture_sha256 = "fc4832f1bc1bdfd322e808ae4929487628981792c23f959c1764c8eaedbfaf7f" (* Same technique tools/bootstrap_sanctoral.ml already uses for this exact purpose (that file's own comment: shelling out to the system's @@ -396,15 +418,21 @@ let diff_fields (l : row) (c : row) = let subset xs ys = List.for_all (fun x -> List.mem x ys) xs let day_of_date date = int_of_string (String.sub date 8 2) -let advent_feria_slug slug = - List.exists - (fun wk -> List.exists (fun wd -> String.equal slug (Printf.sprintf "ef-advent-%d-%s" wk wd)) weekdays) - [ 3; 4 ] - -let sunday_iclass_slugs = - [ "ef-advent-sunday-2"; "ef-advent-sunday-4"; "ef-lent-sunday-1"; "ef-lent-sunday-2"; "ef-lent-sunday-3" ] - -let rose_sunday_slugs = [ "ef-advent-sunday-3"; "ef-lent-sunday-4" ] +(* ef-rebootstrap fixture refresh (2026-08-12): C2, C3, C4, C5, C7, C10, C11, + C12 and C13's own predicates/helper bindings (sunday_iclass_slugs, + rose_sunday_slugs, advent_feria_slug, fixed_iii_class_reclassified_slugs, + jan13_lord_sunday_dates_2005_2050, and the inline C7/C10/C11 date/slug + checks) are REMOVED here, not left dead -- each matched zero rows against + the refreshed fixture (lectio's own fix wave, 2386a45 -> 3b32c00, + independently fixed the exact defects these entries were about), so their + citations moved to docs/research/rules-register.md (closure record, with + the RG paragraph preserved) and their sexp rows to nothing -- + data/ef/expected-divergences.sexp no longer declares those ids at all. + Removing a predicate strengthens this harness the same way removing its + sexp row does: if any of these nine shapes ever reappears (a regression in + colitur, or lectio moving again), it now surfaces as UNEXPLAINED instead + of being silently re-absorbed by a citation whose own divergence no + longer exists. *) (* Fix round 1, finding 1: C1 and C6 (below) originally gated on calendar date alone, with no slug/slug-family check -- unlike every other entry @@ -427,40 +455,21 @@ let jan_6_13_slug slug = let nativity_octave_day_slugs = [ "ef-nativity-octave-day-5"; "ef-nativity-octave-day-6"; "ef-nativity-octave-day-7" ] -(* C12 (ef-rebootstrap, 2026-08-12): the exact 15 slugs data/ef/sanctoral.sexp - re-bootstrapped from `rank = commemoration` to a real class-3 feast (the - source's own SHA-256 moved 6a25e634... -> 1b303ef2...) -- a literal list, - not a date-range or slug-prefix pattern, per the SAME discipline the - comment above this one already states for C1/C6 (fix round 1, finding 1): - a slug outside this exact set must fail through to [None], not be - silently absorbed by a citation about a different set of saints. Only 7 - of the 15 are ever actually reachable here (the other 8 never collide - with a plain class-4 feria anywhere in 2005-2050), but the guard is - written against the full set colitur's own data now carries, not the - narrower subset this one 46-year window happens to exercise. *) -let fixed_iii_class_reclassified_slugs = - [ "benedict"; "cyril-of-jerusalem"; "forty-holy-martyrs-of-sebaste"; "frances-rome"; - "francis-of-paola"; "gabriel-the-archangel"; "gregory-the-great"; "isidore-of-seville"; - "john-damascene"; "john-of-capistrano"; "john-of-god"; "patrick"; "sts-felicitas-perpetua"; - "thomas-aquinas"; "vincent-ferrer" ] - -(* C13 (ef-rebootstrap fix round 1, F2): the 7 years 13 January falls on a - Sunday within 2005-2050 -- independently re-derived, not copied from a - prior figure: `date -d <year>-01-13 +%A` = Sunday in exactly these 7 - (2005-2050 is 46 years; 13 January cycles through the 7 weekdays with - the usual leap-year irregularity, landing on Sunday this many times). - A LITERAL list, not a predicate on [jan_6_13_slug] (which already, and - correctly, admits this exact slug for the other 39 non-Sunday years in - the window) -- checked BEFORE C1 below in the if/elif chain specifically - so it intercepts these 7 dates first; leaving C1's own guard as it was - would have let [jan_6_13_slug]'s pre-existing admission of this slug - silently absorb them into C1's count instead, the exact gap fix round 1 - found: C1's own [expected_rows] is a bare row COUNT, blind to WHICH of - two different diff shapes produced it, so a real shape change here - (colitur's own OBSERVED CELEBRATION on these 7 dates, not merely its - colour) could move underneath the pin without the pin ever moving. *) -let jan13_lord_sunday_dates_2005_2050 = - [ "2008-01-13"; "2013-01-13"; "2019-01-13"; "2030-01-13"; "2036-01-13"; "2041-01-13"; "2047-01-13" ] +(* C14 (ef-rebootstrap fixture refresh, 2026-08-12; replaces the closed C9, + see data/ef/expected-divergences.sexp's own C14 note for the full RG + citation): the exact 3 civil days, across the whole 2005-2050 window, + where St Joseph's (19 March, I class) RG 96 transfer walk is congested + enough by Passiontide/Holy Week/the Easter octave to cross Easter AND + collide with the Annunciation's own transferred "sedes propria" (RG 96 + Attamen (a), Monday after Low Sunday) -- independently re-derived from + this fixture and colitur's own output (`grep joseph-spouse` both sides, + filtered to rows with a real post-Layer-A/B diff), not copied from the + register's prior "2008, 2035, 2046" prose. A LITERAL date list, not a + slug predicate, per the SAME discipline C12/C13 already used (a plain + "involves this slug" predicate is exactly what let the old C9 silently + cover two textually-unrelated divergences at once -- see C14's own sexp + note for the full account of why that was wrong). *) +let joseph_annunciation_collision_dates_2005_2050 = [ "2008-04-01"; "2035-04-03"; "2046-04-03" ] (* [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 @@ -468,50 +477,23 @@ let jan13_lord_sunday_dates_2005_2050 = let layer_c_reason (l : row) (c : row) diffs = let m = month_of_date l.date and d = day_of_date l.date in if diffs = [] then None - else if List.mem l.date jan13_lord_sunday_dates_2005_2050 && diffs = [ Season; Slug_f; Colour_f ] then - Some "C13" else if m = 1 && d >= 6 && d <= 13 && subset diffs [ Season; Colour_f; Slug_f ] && (not (List.mem Slug_f diffs) || jan_6_13_slug c.slug) then Some "C1" - else if List.mem c.slug sunday_iclass_slugs && diffs = [ Rank ] then Some "C2" - else if List.mem c.slug rose_sunday_slugs && subset diffs [ Rank; Colour_f ] then Some "C3" - else if advent_feria_slug c.slug && diffs = [ Rank ] then Some "C4" - else if starts_with ~prefix:"ef-lent-ember-" c.slug && subset diffs [ Slug_f; Rank ] then Some "C5" else if m = 12 && (d = 29 || d = 30 || d = 31) && subset diffs [ Slug_f; Rank ] && (not (List.mem Slug_f diffs) || List.mem c.slug nativity_octave_day_slugs) then Some "C6" - else if (String.equal c.slug "matthew" || String.equal c.slug "thomas") && subset diffs [ Slug_f; Colour_f ] - then Some "C7" else if (String.equal c.slug "ef-rogation-monday" || String.equal c.slug "ef-rogation-tuesday") && subset diffs [ Season; Slug_f; Colour_f ] then Some "C8" - else if - (String.equal l.slug "joseph-spouse-of-the-bl-virgin-mary" - || String.equal c.slug "joseph-spouse-of-the-bl-virgin-mary") - && subset diffs [ Season; Slug_f; Rank; Colour_f ] - then Some "C9" - else if - (String.equal l.date "2011-07-02" || String.equal l.date "2011-07-04") - && subset diffs [ Slug_f; Rank; Colour_f ] - then Some "C10" - else if String.equal c.slug "ef-passiontide-2-thursday" && diffs = [ Colour_f ] then Some "C11" - (* RG16(a) task, fix round 1 (CRITICAL finding): a C12 entry briefly lived - here, allow-listing 2 February on a Sunday against lectio, when - `data/ef/adjustments.sexp` retagged the Purification `Bvm`. REVERTED -- - the user has ruled: follow the oracle (register §6.0 has the full - account). The Purification is `Lord` again, colitur observes it - outright on those six 2-February Sundays, matching lectio's own - `class = lord` exactly -- no divergence to allow-list. That C12 was - removed, not merely unused -- superseded by the DIFFERENT C12 below, - ef-rebootstrap (2026-08-12), reusing the freed id. *) - else if List.mem c.slug fixed_iii_class_reclassified_slugs && subset diffs [ Slug_f; Rank; Colour_f ] - then Some "C12" + else if List.mem l.date joseph_annunciation_collision_dates_2005_2050 && subset diffs [ Slug_f; Rank ] then + Some "C14" else None (* ---------------------------------------------------------------------- *) @@ -591,7 +573,7 @@ let test_dates_align () = in Alcotest.(check (list (pair string string))) "no misaligned dates" [] mismatched -(* The core assertion: every one of the 5595 raw differences is either +(* The core assertion: every one of the 4975 raw differences is either normalised away (Layers A/B) or named in the cited allow-list (Layer C). Nothing else is permitted to pass silently. *) let test_no_unexplained_differences () = |
