summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 13:30:09 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 13:30:09 +0200
commit9b8821f7b914c94f5b2c8eeda05407ee921b3d5a (patch)
tree0aca637921a3792b50e46a2830b869d6b7c4d3ac
parent9cc763c169a6ce4ebbdbed506c5eb2dad1f9f3c1 (diff)
downloadcolitur-9b8821f7b914c94f5b2c8eeda05407ee921b3d5a.tar.gz
colitur-9b8821f7b914c94f5b2c8eeda05407ee921b3d5a.zip
feat(of-lectionary): disclose the citation-conversion residual in the header
Fix option (c) from the I2 review finding, done alongside the parser fix itself rather than deferred: tools/bootstrap_lectionary_of.ml now runs every emitted reference through Colitur_citation.Parse.parse at generation time and adds a fourth COVERAGE item plus a named listing to data/of/lectionary.sexp's own header, so the 41-reference residual (all chapter-crossing hyphen ranges, see the citation-fix commit) is disclosed in the artifact a reader actually opens, not only in a task report or test file. Regenerated against the pinned lectio snapshot (dune exec tools/bootstrap_lectionary_of.exe -- ../lectio/internal/caldata/ of-lectionary.ini data/of/lectionary.sexp); diffed against the pre-change file to confirm the change is header-only, zero lines removed, the sexp payload byte-identical. Re-pins the file's own SHA-256 in test_lectionary_of.ml accordingly (re-derived with sha256sum, not transcribed from generator stdout, matching that test's own stated discipline).
-rw-r--r--data/of/lectionary.sexp56
-rw-r--r--test/test_lectionary_of.ml9
-rw-r--r--tools/bootstrap_lectionary_of.ml49
-rw-r--r--tools/dune7
4 files changed, 118 insertions, 3 deletions
diff --git a/data/of/lectionary.sexp b/data/of/lectionary.sexp
index 167a7c7..8cc1d63 100644
--- a/data/of/lectionary.sexp
+++ b/data/of/lectionary.sexp
@@ -75,9 +75,65 @@
; ferial (Lectionary_of.readings' own step 2 -> step 3) -- this is
; OLM norms working as designed for a saint with no proper of
; their own, not a gap in this data.
+; (4) Citation-siglum conversion (fix wave I2, 2026-08-26 review): of
+; 1540 emitted (First, Gospel) citation fields, 41 distinct
+; references (out of the full 1540) do not parse -- every one a
+; hyphen range that crosses a chapter boundary ("2:29-3:6"), a
+; {!Colitur_citation.Parse.t} shape this parser's [part]/
+; [verse_range] types do not represent, deliberately not built
+; this task (see book.ml's own [is_single_chapter] neighbourhood
+; for what WAS fixed: 345 previously-unregistered book names and
+; verse sub-letter markers, both closed at the parser/book-table
+; level, not here). Such a reference still prints, verbatim,
+; never a crash or a dropped citation -- {!Colitur_citation.Sigla
+; .format}'s own documented contract on a parse miss. Pinned
+; exactly, both directions, by test/test_citation_coverage_of.ml.
+; Named below.
; Regenerate with:
; eval $(opam env) && dune exec tools/bootstrap_lectionary_of.exe -- ../lectio/internal/caldata/of-lectionary.ini data/of/lectionary.sexp
; Unmapped lectio bases (0):
+; Citations that do not parse (41 distinct, all chapter-crossing ranges):
+; 1 Corinthians 12:31-13:13
+; 1 John 1:5-2:2
+; 1 John 2:29-3:6
+; 1 John 3:22-4:6
+; 1 John 4:19-5:4
+; 2 Corinthians 3:15-4:1,3-6
+; 2 Samuel 18:9-10,14b,24-25a,30-19:3
+; Colossians 1:24-2:3
+; Ecclesiastes 11:9-12:8
+; Ephesians 4:32-5:8
+; Exodus 11:10-12:14
+; Exodus 14:21-15:1
+; Ezekiel 2:8-3:4
+; Galatians 4:22-24,26-27,31-5:1
+; Genesis 1:1-2:2
+; Genesis 1:20-2:4a
+; Habakkuk 1:12-2:4
+; Hebrews 7:25-8:6
+; Isaiah 52:13-53:12
+; Isaiah 8:23b-9:3
+; John 15:26-16:4a
+; John 18:1-19:42
+; Jonah 1:1-2:2,11
+; Luke 7:36-8:3
+; Malachi 1:14b-2:2b,8-10
+; Mark 2:23-3:6
+; Mark 8:34-9:1
+; Matthew 10:34-11:1
+; Matthew 18:21-19:1
+; Matthew 9:35-10:1,5a,6-8
+; Matthew 9:36-10:8
+; Numbers 13:1-2,25-14:1,26a-29a,34-35
+; Philippians 3:17-4:1
+; Revelation 20:1-4,11-21:2
+; Sirach 27:30-28:7
+; The Acts 12:24-13:5a
+; The Acts 17:15,22-18:1
+; The Acts 7:51-8:1a
+; Wisdom 11:22-12:2
+; Wisdom 2:23-3:9
+; Wisdom 7:22b-8:1
; Temporal_of slugs (2004-2051) with no lectionary entry (1, informational --
; most are the Christmas-season/late-Advent date-vs-weekday gap named above):
; of-nativity
diff --git a/test/test_lectionary_of.ml b/test/test_lectionary_of.ml
index 03838be..a9fcdb1 100644
--- a/test/test_lectionary_of.ml
+++ b/test/test_lectionary_of.ml
@@ -178,8 +178,15 @@ let sha256_of_file path =
don't transcribe it from generator stdout" discipline
test_calendar_of_data.ml's own [test_sha256] already follows. *)
let test_sha256_pinned () =
+ (* Fix wave I2 (final-review.md, 2026-08-25-colitur-of-phases-3-5): the
+ hash changed because the header grew a new "Citation-siglum
+ conversion" census -- the payload (parse this test's siblings assert
+ against) is byte-identical; only the disclosure comment above it is
+ new. Re-derived with `sha256sum data/of/lectionary.sexp`, not
+ transcribed from generator stdout, the same discipline this test's own
+ header states. *)
Alcotest.(check string) "data/of/lectionary.sexp SHA-256"
- "2277e3dc302e853d78b72608884f59eb67671bfdcca4f5e4c99358ee12811f89" (sha256_of_file lectionary_path)
+ "aba7817ace8add740a5722f5fdb401a119869545eda9082e41e203df4ac27ee5" (sha256_of_file lectionary_path)
(* lectio's OWN of-lectionary.ini SHA-256, pinned inside data/of/
lectionary.sexp's own provenance header (tools/bootstrap_lectionary_of
diff --git a/tools/bootstrap_lectionary_of.ml b/tools/bootstrap_lectionary_of.ml
index da37bd9..a679b01 100644
--- a/tools/bootstrap_lectionary_of.ml
+++ b/tools/bootstrap_lectionary_of.ml
@@ -825,6 +825,34 @@ let temporal_day_gap ~lectionary ~year_start =
done;
(!count, !total, List.rev !misses)
+(* Fix wave I2 (final-review.md, 2026-08-25-colitur-of-phases-3-5): every
+ reference this file emits, run through the SAME parser [colitur readings]
+ itself uses to convert to Latin sigla ({!Colitur_citation.Sigla.format}
+ -> {!Colitur_citation.Parse.parse} on a miss). Disclosed here, at
+ generation time, rather than left for a reader to discover as a silent
+ "- | -"-shaped surprise or an unconverted English fragment sitting next
+ to Latin ones -- this is what I2's own review finding asked for as the
+ minimum acceptable fix if full conversion could not be reached, and it
+ was not: see test/test_citation_coverage_of.ml for the pinned, exact
+ residual and book.ml's own citation for why it remains (chapter-crossing
+ hyphen ranges -- "2:29-3:6" -- a {!Colitur_citation.Parse.t} shape this
+ parser does not represent, deliberately not built this task; every OTHER
+ shape this file's data used to expose, including 345 previously-
+ unregistered book names, is now fixed at the source). *)
+let citation_conversion_census lect =
+ let total = ref 0 and bad = ref [] in
+ List.iter
+ (fun (_slug, cits) ->
+ List.iter
+ (fun (c : Citation.t) ->
+ incr total;
+ match Colitur_citation.Parse.parse c.Citation.reference with
+ | Ok _ -> ()
+ | Error _ -> if not (List.mem c.Citation.reference !bad) then bad := c.Citation.reference :: !bad)
+ cits)
+ (Lectionary.entries lect);
+ (!total, List.sort compare !bad)
+
let sha256 path =
let ic = Unix.open_process_in (Printf.sprintf "sha256sum %s" (Filename.quote path)) in
let line = try input_line ic with End_of_file -> die "sha256sum failed" in
@@ -846,6 +874,7 @@ let () =
let gap_count, gap_total, gap_misses =
temporal_day_gap ~lectionary:lect ~year_start:Rite_of.Temporal_of.year_start
in
+ let cit_total, cit_bad = citation_conversion_census lect in
let oc = open_out dst in
Printf.fprintf oc
"; data/of/lectionary.sexp -- OF (2002) temporal + sanctoral lectionary\n\
@@ -926,15 +955,33 @@ pairs -> %d colitur slugs mapped, %d ini bases genuinely excluded (structurally\
; ferial (Lectionary_of.readings' own step 2 -> step 3) -- this is\n\
; OLM norms working as designed for a saint with no proper of\n\
; their own, not a gap in this data.\n\
+ ; (4) Citation-siglum conversion (fix wave I2, 2026-08-26 review): of\n\
+ ; %d emitted (First, Gospel) citation fields, %d distinct\n\
+ ; references (out of the full %d) do not parse -- every one a\n\
+ ; hyphen range that crosses a chapter boundary (\"2:29-3:6\"), a\n\
+ ; {!Colitur_citation.Parse.t} shape this parser's [part]/\n\
+ ; [verse_range] types do not represent, deliberately not built\n\
+ ; this task (see book.ml's own [is_single_chapter] neighbourhood\n\
+ ; for what WAS fixed: 345 previously-unregistered book names and\n\
+ ; verse sub-letter markers, both closed at the parser/book-table\n\
+ ; level, not here). Such a reference still prints, verbatim,\n\
+ ; never a crash or a dropped citation -- {!Colitur_citation.Sigla\n\
+ ; .format}'s own documented contract on a parse miss. Pinned\n\
+ ; exactly, both directions, by test/test_citation_coverage_of.ml.\n\
+ ; Named below.\n\
; Regenerate with:\n\
; eval $(opam env) && dune exec tools/bootstrap_lectionary_of.exe -- %s %s\n"
src (sha256 src) (List.length secs) (List.length resolved) report.mapped
(List.length excluded_bases) (List.length report.unmapped) (List.length entries)
gap_total gap_count (List.length report.unmapped) (List.length resolved)
(Hashtbl.length sanctoral_slugs) report.sanctoral_passthrough
- (Hashtbl.length sanctoral_slugs - report.sanctoral_passthrough) src dst;
+ (Hashtbl.length sanctoral_slugs - report.sanctoral_passthrough)
+ cit_total (List.length cit_bad) cit_total src dst;
Printf.fprintf oc "; Unmapped lectio bases (%d):\n" (List.length report.unmapped);
List.iter (fun b -> Printf.fprintf oc "; %s\n" b) report.unmapped;
+ Printf.fprintf oc "; Citations that do not parse (%d distinct, all chapter-crossing ranges):\n"
+ (List.length cit_bad);
+ List.iter (fun r -> Printf.fprintf oc "; %s\n" r) cit_bad;
Printf.fprintf oc "; Temporal_of slugs (2004-2051) with no lectionary entry (%d, informational --\n\
; most are the Christmas-season/late-Advent date-vs-weekday gap named above):\n"
(List.length uncovered_temporal);
diff --git a/tools/dune b/tools/dune
index 40e9836..7cf4440 100644
--- a/tools/dune
+++ b/tools/dune
@@ -34,9 +34,14 @@
; sanctoral_slugs] reads data/of/calendar-2002.sexp and data/of/amendments/
; by a repo-root-relative path, unlike bootstrap_lectionary.ml's own
; source/dest arguments, which are caller-supplied).
+; `colitur_citation` (fix wave I2, final-review.md): the emitted header now
+; runs every emitted reference through Colitur_citation.Parse.parse itself
+; and names the count and the exact set that fail, so the limit is
+; disclosed in the artifact a reader actually sees rather than only in a
+; task report.
(executable
(name bootstrap_lectionary_of)
- (libraries colitur_kernel rite_of unix sexplib))
+ (libraries colitur_kernel colitur_citation rite_of unix sexplib))
; Task 6 (2026-08-21-colitur-celebrant-rubrics-phase1): turns pdftotext's
; -layout dump of the Latin Mass Society Ordo into test/fixtures/