From 25fedcaf3044828333ba15b232fdc7c7f84970e5 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 12 Aug 2026 17:49:11 +0200 Subject: data(ef): re-bootstrap sanctoral.sexp from the corrected lectio source Regenerated via tools/bootstrap_sanctoral.ml against lectio's tridentine-calendar.ini (SHA-256 6a25e634... -> 1b303ef2...), whose own generator was independently fixed in a concurrent session. 327 entries (223 feast, 104 commemoration-only), up from 322 (208/114): - 15 entries wrongly bootstrapped `rank = commemoration` are now `class-3` (a real III-class Feast) -- all 6 March-5 April, all primary-source-verified against the calendarium (register's own "Commemoration-only entries' inferred STATUS" item). - 5 new entries: agnes-secundo (28 Jan), boniface-martyr (14 May), eusebius-confessor (14 Aug), evaristus (26 Oct), theodore (9 Nov) -- all Commemoration_only, all primary-source-verified (register's "Four confirmed sanctoral DATA GAPS" item + expected-divergences-missalemeum .sexp's former M4/M6/M7/M9/M14). - commemoration-of-the-baptism-of-the-lord (13 Jan) is now `(subject Lord)` (the source's own `class` field, not a colitur overlay); most-holy-name-of-mary (12 Sep) no longer carries `class = lord` at all (the source dropped it), so the bootstrap default (Subject.Saint) is now correct there without help from adjustments.sexp's own Edit. test_sanctoral_ef.ml's pinned counts (327/104/12 Class1) are re-derived directly from the source INI (`grep -c '^\['`, `grep '^rank' | sort | uniq -c`), not transcribed from a bootstrap-tool or `colitur day` run. data/ef/adjustments.sexp and the differential/oracle allow-lists still need updating for the consequences of this regeneration -- follow-up commits. --- test/test_sanctoral_ef.ml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'test/test_sanctoral_ef.ml') diff --git a/test/test_sanctoral_ef.ml b/test/test_sanctoral_ef.ml index 8fb178f..24ed972 100644 --- a/test/test_sanctoral_ef.ml +++ b/test/test_sanctoral_ef.ml @@ -28,13 +28,25 @@ let load () = let mkdate m d = match DS.fixed ~month:m ~day:d with Ok t -> t | Error e -> failwith e +(* Counts re-derived 2026-08-12 (ef-rebootstrap) against the regenerated + source INI directly (`grep -c '^\['` minus the [layer] header itself; + `grep '^rank' | sort | uniq -c`) -- NOT copied from a `colitur day`/ + bootstrap-tool run, per this project's own "derive the new value, don't + transcribe it from output" pinning discipline. The source's SHA-256 moved + 6a25e634... -> 1b303ef2..., correcting: 15 entries wrongly `rank = + commemoration` that are really class-3 feasts (322 -> 327's own feast/ + comm split moves 15 the other way before the net +5 below); 5 entries + newly present (agnes-secundo, boniface-martyr, eusebius-confessor, + evaristus, theodore -- all Commemoration_only), so 322 + 5 = 327 and + 114 - 15 + 5 = 104. Class1 count (12) is untouched by this regeneration -- + none of the 20 changed/added entries is Class1. *) let test_load_and_counts () = let l = load () in - Alcotest.(check int) "322 entries" 322 (List.length l.L.entries); + Alcotest.(check int) "327 entries" 327 (List.length l.L.entries); let commemoration_only = List.filter (fun e -> e.L.cel.Cel.status = Cel.Commemoration_only) l.L.entries in - Alcotest.(check int) "114 Commemoration_only" 114 (List.length commemoration_only); + Alcotest.(check int) "104 Commemoration_only" 104 (List.length commemoration_only); let class1 = List.filter (fun e -> e.L.cel.Cel.rank = V.Class1) l.L.entries in Alcotest.(check int) "12 Class1" 12 (List.length class1); let temporal_subjects = List.filter (fun e -> e.L.cel.Cel.subject = Sub.Temporal) l.L.entries in -- cgit v1.3 From dbde8523f2ec2f0db4d2619afed8575ccf8a3641 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 12 Aug 2026 18:26:21 +0200 Subject: test(sanctoral_ef): fix round 1 (F8) -- guard against wholesale name.pl loss The previous commit's bootstrap_sanctoral.ml change (name.pl optional) is correct and verified not to silently drop a present name, but nothing in the suite would have caught a regeneration that dropped name.pl WHOLESALE -- the exact defect lectio itself shipped once (a regeneration that lost all 322 Polish names, only caught because that project's own review ran cmd/lectio-ef-dump, which happens to include name fields; this project's own test_load_and_counts checks entry/status/rank counts only, none of which move if every name.pl vanishes). Added a 322-of-327 count assertion (5 legitimately lack it, matching parse_names's own list), independently re-derived: `grep -c '^name.pl' tridentine-calendar.ini` = 322, cross-checked against `grep -c '(pl' data/ef/sanctoral.sexp` = 322 exactly. --- test/test_sanctoral_ef.ml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'test/test_sanctoral_ef.ml') diff --git a/test/test_sanctoral_ef.ml b/test/test_sanctoral_ef.ml index 24ed972..e3b34a6 100644 --- a/test/test_sanctoral_ef.ml +++ b/test/test_sanctoral_ef.ml @@ -51,6 +51,27 @@ let test_load_and_counts () = Alcotest.(check int) "12 Class1" 12 (List.length class1); let temporal_subjects = List.filter (fun e -> e.L.cel.Cel.subject = Sub.Temporal) l.L.entries in Alcotest.(check int) "no Subject.Temporal" 0 (List.length temporal_subjects); + (* ef-rebootstrap fix round 1 (F8): a guard against WHOLESALE Polish-name + loss, the exact defect lectio itself shipped once (a regeneration that + dropped all 322 name.pl entries, the "SECOND Critical" the lectio side + of this session's own work found and fixed -- register/ledger record). + `parse_names`'s own `field_opt` change (this task's first commit) can + legitimately drop to en-only for a genuinely pl-less source entry -- + verified NOT to silently drop a PRESENT name -- but nothing before + this assertion would have caught a regeneration that dropped pl + WHOLESALE the way lectio's once did: `test_load_and_counts` checked + entry/status/rank counts only, none of which move if every name.pl + vanishes. Independently re-derived, not transcribed: `grep -c + '^name.pl' tridentine-calendar.ini` = 322 (327 entries, 5 lack it -- + the same 5 `parse_names` documents), cross-checked against + `grep -c '(pl' data/ef/sanctoral.sexp` = 322 exactly. *) + let with_pl = + List.filter + (fun e -> Names.find e.L.cel.Cel.names (Lang.of_string_exn "pl") <> None) + l.L.entries + in + Alcotest.(check int) "322 of 327 entries carry a Polish name (5 legitimately do not)" 322 + (List.length with_pl); (* Every slug already had to pass Slug.of_string during load (Slug.t_of_sexp is the validating parser -- an invalid slug would have failed the whole Layer.load with Error, never landing here silently). Re-checking is -- cgit v1.3