From a4eb9ed3cd93cbac493a873991dd5817906aad56 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 20 Aug 2026 14:54:01 +0200 Subject: fix(citation): survey all three citation-bearing files, not just the lectionary The book table was built against data/ef/lectionary.sexp alone. That undercounts: sanctoral.sexp carries more citations than the lectionary and, together with commons.sexp, cites 21 book tokens the table was missing entirely (62 distinct tokens across all three files, not 42), several of them common (2 Tim appears 8+ times). Add the missing spellings to existing ids (2 Cor, Col., Exod, Ezek, James, Sir, Eccli) and ten new ids for books not cited before (1-2 Timothy, 2 Peter, Apocalypse, Judith, Malachi, Proverbs, Song of Songs, Tobit, Wisdom). Sir and Rev are modern spellings sitting inside Vulgate data, so both resolve to their Vulgate ids (ecclesiasticus, apocalypse) rather than to the sirach/revelation tradition targets -- mapping them to a second id would double-map the same book. Add a duplicate-spelling invariant test (List.assoc_opt would silently prefer the first match on a collision) and a test that re-derives the token set from all three data files at test time and asserts every token resolves, rather than trusting a survey performed once by hand. --- lib/citation/book.ml | 47 ++++++++++++++++++++++++++++++++++++----------- lib/citation/book.mli | 21 ++++++++++++++++----- 2 files changed, 52 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/citation/book.ml b/lib/citation/book.ml index a2f9678..545e324 100644 --- a/lib/citation/book.ml +++ b/lib/citation/book.ml @@ -4,25 +4,36 @@ type id = string let to_string t = t -(* Every book the shipped EF lectionary cites, with every spelling it uses. - The dotted/undotted pairs are inherited from lectio -- see book.mli. *) +(* Every book cited across the shipped EF data (lectionary, sanctoral + propers, and commons), with every spelling any of the three files uses. + The dotted/undotted and modern/Vulgate pairs are inherited from lectio -- + see book.mli. Surveyed directly against the data, all three files, not + the lectionary alone -- sanctoral.sexp alone carries more citations than + the lectionary and was the source of every token missed in the first + pass. *) let table = [ ("genesis", [ "Gen" ]); - ("exodus", [ "Ex" ]); + ("exodus", [ "Ex"; "Exod" ]); ("leviticus", [ "Lev" ]); ("numbers", [ "Num" ]); ("kings_3", [ "3 Kings"; "3 Kgs." ]); ("kings_4", [ "4 Kings" ]); ("esdras_2", [ "2 Esd." ]); + ("tobit", [ "Tob" ]); + ("judith", [ "Judith" ]); ("esther", [ "Esther" ]); - ("ecclesiasticus", [ "Ecclus" ]); + ("proverbs", [ "Prov" ]); + ("song_of_songs", [ "Song" ]); + ("wisdom", [ "Wis"; "Wis." ]); + ("ecclesiasticus", [ "Ecclus"; "Sir"; "Eccli" ]); ("isaiah", [ "Isa"; "Isa." ]); ("jeremiah", [ "Jer" ]); - ("ezekiel", [ "Ezech" ]); + ("ezekiel", [ "Ezech"; "Ezek" ]); ("daniel", [ "Dan" ]); ("osee", [ "Osee" ]); ("joel", [ "Joel" ]); ("jonas", [ "Jonas" ]); + ("malachi", [ "Mal" ]); ("matthew", [ "Matt"; "Matt." ]); ("mark", [ "Mark" ]); ("luke", [ "Luke" ]); @@ -30,23 +41,37 @@ let table = ("acts", [ "Acts" ]); ("romans", [ "Rom" ]); ("corinthians_1", [ "1 Cor"; "1 Cor." ]); - ("corinthians_2", [ "2 Cor." ]); + ("corinthians_2", [ "2 Cor"; "2 Cor." ]); ("galatians", [ "Gal" ]); ("ephesians", [ "Eph"; "Eph." ]); ("philippians", [ "Phil" ]); - ("colossians", [ "Col" ]); + ("colossians", [ "Col"; "Col." ]); ("thessalonians_1", [ "1 Thess"; "1 Thess." ]); ("thessalonians_2", [ "2 Thess" ]); + ("timothy_1", [ "1 Tim." ]); + ("timothy_2", [ "2 Tim"; "2 Tim." ]); ("titus", [ "Titus" ]); ("hebrews", [ "Heb" ]); - ("james", [ "Jas" ]); + ("james", [ "Jas"; "James" ]); ("peter_1", [ "1 Pet"; "1 Pet." ]); - ("john_1", [ "1 John" ]) ] + ("peter_2", [ "2 Pet." ]); + ("john_1", [ "1 John" ]); + (* "Apoc" is the Vulgate spelling and "Rev" its modern equivalent, but + BOTH sit inside Vulgate-tradition data, so both resolve to the same + Vulgate id here -- see book.mli's note by [apocalypse] never being an + [of_token] result under that name. Do not add "revelation" as a + spelling: it exists only as a tradition target (below), and giving it + an [of_token] entry would let one book carry two different ids. *) + ("apocalypse", [ "Apoc"; "Rev" ]) ] (* Targets a tradition can map ONTO that the Vulgate data never cites - directly. Present so [tradition_of_fields] can validate both sides. *) + directly. Present so [tradition_of_fields] can validate both sides. + [sirach] and [revelation] exist ONLY here, never as an [of_token] result: + "Sir" and "Rev" already resolve to the Vulgate ids [ecclesiasticus] and + [apocalypse] above, so a modern-numbering tradition maps ONTO these + targets rather than data ever citing them directly. *) let tradition_targets = - [ "kings_1"; "kings_2"; "nehemiah"; "sirach"; "hosea"; "jonah" ] + [ "kings_1"; "kings_2"; "nehemiah"; "sirach"; "hosea"; "jonah"; "revelation" ] let all = List.map fst table @ tradition_targets diff --git a/lib/citation/book.mli b/lib/citation/book.mli index dd04e0d..8918bc3 100644 --- a/lib/citation/book.mli +++ b/lib/citation/book.mli @@ -15,11 +15,19 @@ val to_string : id -> string (** Resolve one spelling as it appears in the data. Returns [None] for anything not in {!tokens}. - SEVEN books arrive in two spellings ([Isa]/[Isa.], [3 Kgs.]/[3 Kings], - and five more). That inconsistency is INHERITED from lectio's own ini, - which is itself generated from missalemeum/Divinum Officium -- it is not - a colitur transcription error, and the data is deliberately left - untouched. Both spellings resolve here instead. *) + SIXTEEN books arrive in more than one spelling, surveyed across all + three citation-bearing files ([lectionary.sexp], [sanctoral.sexp], + [commons.sexp] -- not the lectionary alone, which undercounts: the + sanctoral propers alone carry more citations than the lectionary does). + Most are a dotted/undotted pair ([Isa]/[Isa.], [3 Kgs.]/[3 Kings], and + others); two also carry a MODERN spelling sitting inside otherwise- + Vulgate data ([Sir] alongside [Ecclus]/[Eccli], [Rev] alongside [Apoc]). + All of this is INHERITED from lectio's own ini, which is itself + generated from missalemeum/Divinum Officium -- it is not a colitur + transcription error, and the data is deliberately left untouched. Every + accepted spelling resolves here to the same, single Vulgate id: [Sir] + resolves to [ecclesiasticus] and [Rev] to [apocalypse], never to the + tradition-only targets [sirach]/[revelation] -- see those below. *) val of_token : string -> id option (** Every id this build knows, for coverage checks. *) @@ -44,6 +52,9 @@ val vulgate : tradition {!unknown_fields} to report them. *) val tradition_of_fields : (string * string) list -> tradition +(** The fields {!tradition_of_fields} silently dropped -- either side naming + an id outside {!all}. Never raises; a caller that cares can report these, + a caller that does not can ignore the return value entirely. *) val unknown_fields : (string * string) list -> string list val map : tradition -> id -> id -- cgit v1.3