From d68feb04f71c3dea3b59726e2ffca225d99eaa35 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 20 Aug 2026 17:14:42 +0200 Subject: feat(lang): Latin and English book names, and the shipped sigla styles la.ini and en.ini both gain [sigla] (the current Vulgate/Latin punctuation convention, byte-identical to Render.default_style) and [bible] (a .full and .abbr row for every id in Book.all -- 45 cited ids plus the 7 tradition targets, 52 total). Shipping [sigla] changes no output, asserted by the full test run. Shipping [bible] does change rendered book names, which is the point. la.ini's titles are sourced from docs/research/scan1.txt/scan2.txt (the 1962 Missal scans), each row citing the line its incipit pattern was read from. Six pairs (kings_3/4, corinthians_1/2, thessalonians_1/2, timothy_1/2, peter_1/2) share one Missal incipit and differ only in the sourced .abbr, matching what the primary text itself does. Three ids (proverbs, song_of_songs, ecclesiasticus) and the seven tradition targets are marked UNSOURCED and fall back to the data's own spelling, per this project's central rule against inventing a Latin title. Re-running the task's own sourcing note against the scans, counting every hit rather than eyeballing a frequency-sorted list, found nine of its NOT-sourced verdicts were undercounted (a single clean hit, buried under higher-frequency matches): Galatians, Colossians, both Thessalonians, both Peter, Malachi, Numbers, Jonas, Osee and Esdras all have a clean incipit in the scans and are sourced here. The note's other three verdicts stand, confirmed independently. Ecclesiasticus is not simply unfound: this Missal reuses Wisdom's own Lectio libri Sapientiae incipit for Ecclesiasticus readings too (both were anciently classed as one Sapiential group), so using it for Ecclesiasticus would misidentify the book, not merely abbreviate it -- recorded in that row's own comment. en.ini's [bible] is filled in full, not left partial the way [celebration] is: without it, a Vulgate-numbered id would fall through the [meta] fallback chain to la.ini's Latin name, not merely a less complete English one. Traditional Douay-Rheims names for the Vulgate ids (3 Kings, Osee, Ecclesiasticus, Isaias, Apocalypse), modern names for the seven tradition targets, since --sigla-tradition modern is the reader asking for modern numbering. test_lang_coverage.ml gains test_every_book_named, asserting every Book.all id has both forms in la.ini -- the check that catches a forgotten tradition target, since nothing else in the suite ever names them. Shipping real book names changes 11 golden template renders (Render/golden) and several test/cli.t examples that used to demonstrate the pre-Task-10 default-spelling fallback; both are updated to the new, correct output, each line checked against a fresh render before promoting. --- lang/la.ini | 375 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) (limited to 'lang/la.ini') diff --git a/lang/la.ini b/lang/la.ini index 536f717..537f9a3 100644 --- a/lang/la.ini +++ b/lang/la.ini @@ -1790,3 +1790,378 @@ rogation-wednesday = Feria IV Rogationum ; PATTERN, because the Missal's own text for this specific day was found ; (Wednesday's own station, "ad S. Petrum") and is transcribed, not built ; by pattern. + +[sigla] +; The Vulgate/Latin citation convention -- abbreviated book, "chapter:verses", +; "first-last" for a verse range, "; " between parts, ", " between verse +; ranges. This is byte-identical to Colitur_citation.Render.default_style +; (render.ml), so shipping this section changes NO rendered output -- Task 9 +; Step 5 already asserted the pre-Task-10 baseline against exactly these +; values. +; book_sep ships as a PLAIN space, not U+00A0 (the non-breaking space): a +; user who wants the non-breaking form for typeset output (so "Luc." and +; "3, 1" never split across a line break) sets it themselves -- see +; Render.book_sep's own note. Written here as a literal space between the +; "=" and the closing quote; it is invisible in a terminal and easy to +; mistake for something else when editing by hand. +book = abbr +book_sep = " " +chapter_verse = {chapter}:{verses} +range = {first}-{last} +part_sep = "; " +verse_sep = ", " + +[bible] +; Task 10. Every id in Colitur_citation.Book.all (lib/citation/book.ml), each +; with a `.full` and an `.abbr` form. +; +; SOURCING METHOD -- do not invent a Latin title. `docs/research/scan1.txt` +; and `docs/research/scan2.txt` are page-image OCR of the 1962 Missale +; Romanum; `docs/research/LT.txt` is an independent electronic transcription +; (accented, ligatured). The Missal never prints a standalone table of book +; names -- what is transcribed below is the TAIL of the reading's own +; incipit, following four recurring patterns, each attested many times +; across both scans: +; "Lectio libri X" -> "Liber X" (OT books) +; "Lectio X Prophetae" -> "X Propheta" (Prophets; +; genitive -> nominative, e.g. "Isaiae" -> "Isaias") +; "Sequentia sancti Evangelii secundum X" -> "Evangelium secundum X" (Gospels) +; "Lectio Epistolae beati Pauli Apostoli ad X" -> "Epistola ad X" (Pauline) +; "Lectio Actuum Apostolorum" -> "Actus Apostolorum" (Acts) +; "Lectio libri Apocalypsis beati Ioannis Apostoli" -> "Liber Apocalypsis" +; "Lectio Epistolae beati N Apostoli" -> "Epistola beati N Apostoli" +; (James, 1 John, 1-2 Peter: no "ad X" destination to shorten to, so +; the attribution stays -- the only thing that identifies the book) +; Every `.full` below cites the scan/line where its pattern was read; every +; `.abbr` cites a clean chapter:verse LOCATOR line (e.g. "3 Reg. 19, 3-8"), +; which is where this Missal's own Latin abbreviations actually live -- the +; incipit itself is never abbreviated. +; +; UNDIFFERENTIATED INCIPITS. Six pairs share ONE Missal incipit regardless of +; which volume/letter is being read -- "Lectio libri Regum" precedes a "3 +; Reg." locator on one page and a "4 Reg." locator on another; likewise +; "...ad Corinthios"/"...ad Timotheum"/"...ad Thessalonicenses"/"Epistolae +; beati Petri Apostoli" never say "prima"/"secunda" or "I"/"II" anywhere in +; the incipit itself (checked: no "prima"/"secunda ad Corinthios/Timotheum" +; and no "I."/"II. ad Corinthios/Timotheum" anywhere in either scan). Each +; pair therefore shares the SAME `.full` and differs only in `.abbr`, which +; the numbered locator DOES distinguish -- kings_3/kings_4, +; corinthians_1/corinthians_2, thessalonians_1/thessalonians_2, +; timothy_1/timothy_2, peter_1/peter_2. This is not a guess filling a gap: +; it is what the primary text itself does. +; +; A CORRECTION TO THIS TASK'S OWN SOURCING NOTE +; (.superpowers/sdd/2026-08-20-colitur-citations/latin-book-titles-sourcing.md). +; Re-running that note's own commands, but counting EVERY hit rather than +; eyeballing the sorted-by-frequency output (which buries a count-of-1 +; match), turned up clean, undamaged incipits the note listed as "NOT +; sourced": Galatians ("ad Galatas.", scan1.txt:22979), Colossians ("ad +; Colossenses.", scan1.txt:7233), both Thessalonians ("ad Thessalonicenses." +; + "1 Thess."/"2 Thess." locators, scan1.txt:8942/5498), both Peter +; ("Epistolae beati Petri Apostoli." + "1 Petri"/"2 Petri" locators, +; scan1.txt:20021/34670), Malachi ("Lectio Malachiae Prophetae.", +; scan1.txt:26697), Numbers ("Lectio libri Numeri.", scan1.txt:9967), Jonas +; ("Lectio Ionae Prophetae.", scan1.txt:11021), Osee ("Lectio Osee +; Prophetae.", scan1.txt:23301) and Esdras/esdras_2 ("Lectio libri Esdrae." +; + "Neh. vel 2 Esdrae 8, 1-10", scan1.txt:23192-23197). Each is used below, +; cited at its own line, in place of the note's UNSOURCED verdict. The +; note's three other verdicts stand, confirmed independently here: Proverbs, +; Song of Songs and Ecclesiasticus (see that row's own note -- Ecclesiasticus +; is not simply "not found", it is actively MASKED by Wisdom's incipit; see +; below) never occur. + +; --- Pentateuch, Historical -------------------------------------------- +genesis.full = Liber Genesis +; scan2.txt:10275, also scan2.txt:48572. +genesis.abbr = Gen +; scan1.txt:7714 "Gen. 3,". +exodus.full = Liber Exodi +; scan2.txt:42195. +exodus.abbr = Ex +; scan1.txt:12610 "Ex. 30,". +leviticus.full = Liber Levitici +; scan1.txt:11171, also scan1.txt:21490/21525/23384. +leviticus.abbr = Levit +; scan2.txt:12179 "Levit. 19,1-2,11-19 et 25". +numbers.full = Liber Numeri +; scan1.txt:9967 -- CORRECTS the sourcing note (see header): "Lectio libri +; Numeri." is clean and unambiguous. +numbers.abbr = Num +; scan1.txt:9968 "Num. 20, 1, 3 et 6-13", same page as the .full citation. +kings_3.full = Liber Regum +; scan1.txt:8376/9116/10341 "Lectio libri Regum." -- see the header's own +; UNDIFFERENTIATED INCIPITS note: this exact phrase, unqualified, precedes +; both a "3 Reg." and a "4 Reg." locator elsewhere in the same Missal. +kings_3.abbr = 3 Reg +; scan1.txt:8376 "3 Reg. 19, 3-8", also scan2.txt:11230/11671. +kings_4.full = Liber Regum +; Shared incipit -- see kings_3.full's own citation and the header note. +kings_4.abbr = 4 Reg +; scan1.txt:9668 "4 Reg. 5, 1-15", also scan1.txt:10636/9771. +esdras_2.full = Liber Esdrae +; scan1.txt:23192 "Lectio libri Esdrae." -- CORRECTS the sourcing note. +esdras_2.abbr = 2 Esdr +; scan1.txt:23197/23260 "Neh. vel 2 Esdrae 8, 1-10" / "2 Esdr. 8" -- the +; Missal's own rubric names this book BOTH ways at once ("Neh. vel 2 +; Esdrae"), the same Nehemiah/2-Esdras identity book.mli documents for the +; `nehemiah` tradition target below. +tobit.full = Liber Tobiae +; scan1.txt:39115. +tobit.abbr = Tob +; scan1.txt:21719 "Tob. 12,". +judith.full = Liber Iudith +; scan1.txt:28467, also 35356/36937. Spelled "Iudith" (consonantal I), the +; spelling this file's own header note already establishes throughout, and +; the spelling the Missal itself prints -- the "Judith" scan2.txt hit at +; line 39510 is the damaged "ludith" (lowercase L for capital I) the sourcing +; note warns about, not used here. +judith.abbr = Iudith +; scan1.txt:25116 "Iudith 13,", also 25141/27112. +esther.full = Liber Esther +; scan1.txt:9168. +esther.abbr = Esth +; scan1.txt:9170 "Esth. 13, 8-11 et 15-17". +proverbs.full = Prov +proverbs.abbr = Prov +; UNSOURCED -- no "Proverbia"/"Liber Proverbiorum" instance anywhere in +; either scan (checked: `grep -ohE 'Proverbi[a-z]*' docs/research/*.txt` +; returns nothing). `.full`/`.abbr` both fall back to +; Colitur_citation.Book.default_spelling "proverbs" = "Prov", the data's own +; spelling, per this task's own rule for an unsourced row. +song_of_songs.full = Song +song_of_songs.abbr = Song +; UNSOURCED -- no "Canticum Canticorum" instance anywhere in either scan +; (checked: `grep -ohE 'Canticorum' docs/research/*.txt` returns nothing). +; Falls back to Book.default_spelling "song_of_songs" = "Song". +wisdom.full = Liber Sapientiae +; scan2.txt:32982 "Lectio libri Sapientiae" immediately followed by "Sap. +; 5,1-5" -- picked deliberately over other "Lectio libri Sapientiae" hits +; because its OWN locator confirms it is genuinely a Wisdom reading, not an +; Ecclesiasticus one; see ecclesiasticus.full's own note just below for why +; that check matters here specifically. +wisdom.abbr = Sap +; scan1.txt:5929 "Sap. 18, 14-15", also 19909/21271/21390/22852. +ecclesiasticus.full = Ecclus +ecclesiasticus.abbr = Ecclus +; UNSOURCED, and NOT a simple "not found" -- a real finding, not a gap in +; the search. This Missal reuses WISDOM's OWN incipit, "Lectio libri +; Sapientiae", for Ecclesiasticus readings too (both books were anciently +; classed together as "libri Sapientiales"): scan2.txt:32807/44414/44832 all +; read "Lectio libri Sapientiae" and are immediately followed by an +; "Eccli. NN" locator, not a "Sap. NN" one (e.g. scan2.txt:44414-44417, +; "Lectio libri Sapientiae" / "Eccli. 44, ..."). So Ecclesiasticus's OWN +; distinct title never actually appears in this Missal's incipit text -- +; using "Liber Sapientiae" here would misidentify the book, not merely +; abbreviate it, unlike the UNDIFFERENTIATED INCIPITS above (those genuinely +; are the same book, just a different volume/letter). The abbreviated +; locator form "Eccli." IS independently attested (same citations) and +; matches this id's own third data spelling (book.ml: "Ecclus"; "Sir"; +; "Eccli") -- recorded here for a future reviewer, but not used for `.abbr`, +; to keep this row's two fields consistent with the plain +; sourced-or-not-sourced rule the rest of this file follows. + +; --- Prophets ------------------------------------------------------------- +isaiah.full = Isaias Propheta +; scan1.txt:8276 "Lectio Isaiae Propheta[e]." (genitive "Isaiae" -> +; nominative "Isaias", the Missal's own most frequent prophetic incipit). +isaiah.abbr = Isai +; scan1.txt:4947 "Isai. 30,", also 5062/5080. +jeremiah.full = Ieremias Propheta +; scan1.txt:9939 "Lectio Ieremiae Propheta[e]." +jeremiah.abbr = Ier +; scan1.txt:9271 "Ier. 17,", also 9940. +ezekiel.full = Ezechiel Propheta +; scan1.txt:8518 "Lectio Ezechielis Propheta[e]." +ezekiel.abbr = Ezech +; scan1.txt:8138 "Ezech. 34,", also 8431/8519. +daniel.full = Daniel Propheta +; scan1.txt:9006 "Lectio Danielis Propheta[e]." +daniel.abbr = Dan +; scan1.txt:4613 "Dan. 3,", also 5348/8699. +osee.full = Osee Propheta +; scan1.txt:23301 "Lectio Osee Prophetae." -- CORRECTS the sourcing note; +; "Osee" is indeclinable, same form in the incipit and the locator. +osee.abbr = Osee +; scan1.txt:23301 "Osee 14, 2-10", same line as the .full citation. +joel.full = Ioel Propheta +; scan1.txt:7730 "Lectio Ioelis Propheta[e]." +joel.abbr = Ioel +; scan1.txt:7681 "Ioel. 2,", also 21372. +jonas.full = Ionas Propheta +; scan1.txt:11021 "Lectio Ionae Prophetae." -- CORRECTS the sourcing note +; (genitive "Ionae" -> nominative "Ionas"). +jonas.abbr = Ionae +; scan1.txt:11022 "Ionae 3, 1-10", same page as the .full citation -- the +; Missal's own locator uses the genitive form directly, unabbreviated. +malachi.full = Malachias Propheta +; scan1.txt:26697 "Lectio Malachiae Prophetae." -- CORRECTS the sourcing +; note (genitive "Malachiae" -> nominative "Malachias"). +malachi.abbr = Malach +; scan1.txt:26701 "Malach. 3, 1-4", same page as the .full citation. + +; --- Gospels ---------------------------------------------------------- +matthew.full = Evangelium secundum Matthaeum +; scan1.txt:11892 "secundum Matthaeum.", one of many clean instances. +matthew.abbr = Matth +; scan1.txt:6713 "Matth. 2,", also 6994/7957. +mark.full = Evangelium secundum Marcum +; scan1.txt:12191/12202. +mark.abbr = Marc +; scan1.txt:8007 "Marc. 6,", also 12626/12658. +luke.full = Evangelium secundum Lucam +; scan1.txt:12431/12439. +luke.abbr = Luc +; scan1.txt:4912 "Luc. 21,", also 5148/5426. +john.full = Evangelium secundum Ioannem +; scan1.txt:3843-3844 "dicto Evangelio secundum Ioannem" / "Initium sancti +; Evangelii secundum Ioannem" (O Salutaris/rubrics section, clean, unlike +; the many "lodnnem" OCR breaks the sourcing note warns about elsewhere). +john.abbr = Ioann +; scan1.txt:6125 "Ioann. 21,", also 6372/7112. + +; --- Acts ------------------------------------------------------------- +acts.full = Actus Apostolorum +; scan1.txt:5992 "Lectio Actuum Apostolorum.", also 6566/19649/19748/19827. +acts.abbr = Act +; scan1.txt:5994 "Act. 6,", also 6009/6041. + +; --- Pauline epistles --------------------------------------------------- +romans.full = Epistola ad Romanos +; scan1.txt:5636-5637 "Lectio Epistolae beati Pauli Apostoli / ad Romanos." +romans.abbr = Rom +; scan1.txt:4878 "Rom. 13,", also 4972/6880. +corinthians_1.full = Epistola ad Corinthios +; scan1.txt:5576 "Lectio Epistolae beati Pauli Apostoli / ad Corinthios." -- +; see the header's UNDIFFERENTIATED INCIPITS note. +corinthians_1.abbr = 1 Cor +; scan1.txt:5576 "1 Cor. 4, 1-5", also 19561/21847. +corinthians_2.full = Epistola ad Corinthios +; Shared incipit -- see corinthians_1.full's own citation. +corinthians_2.abbr = 2 Cor +; scan1.txt:22755 "2 Cor. 3, 4-9", also 8068/29417/31759. +galatians.full = Epistola ad Galatas +; scan1.txt:22979 "Lectio Epistolae beati Pauli Apostoli / ad Galatas." -- +; CORRECTS the sourcing note. +galatians.abbr = Gal +; scan1.txt:5902 "Gal. 4,", also 10243/12177. +ephesians.full = Epistola ad Ephesios +; scan1.txt:9573 "Lectio Epistolae beati Pauli Apostoli / ad Ephesios." +ephesians.abbr = Ephes +; scan1.txt:9575 "Ephes. 5, 1-9", also 22040/23017 ("Eph." also occurs, +; scan1.txt:20624, but "Ephes" is the form used at the same instance as the +; .full citation above). +philippians.full = Epistola ad Philippenses +; scan1.txt:43961-43962 "Lectio Epistolae beati Pauli Apostoli / ad +; Philippenses.", also 11827/23947. +philippians.abbr = Phil +; scan1.txt:5025 "Phil. 4,", also 6539. +colossians.full = Epistola ad Colossenses +; scan1.txt:7233 "Lectio Epistolae beati Pauli Apostoli / ad Colossenses." +; -- CORRECTS the sourcing note. +colossians.abbr = Col +; scan1.txt:6798 "Col. 3,", also 7234/15349. +thessalonians_1.full = Epistola ad Thessalonicenses +; scan1.txt:8942-8944 "Lectio Epistolae beati Pauli Apostoli / ad +; Thessalonicenses. 1 Thess. 4,1-7" -- CORRECTS the sourcing note; see the +; header's UNDIFFERENTIATED INCIPITS note. +thessalonians_1.abbr = 1 Thess +; scan1.txt:8944, same line as the .full citation. +thessalonians_2.full = Epistola ad Thessalonicenses +; scan1.txt:5498-5500 "Lectio Epistolae beati Pauli Apostoli / ad +; Thessalonicenses. 2 Thess. 2,1-8" -- CORRECTS the sourcing note. +thessalonians_2.abbr = 2 Thess +; scan1.txt:5500, same line as the .full citation. +timothy_1.full = Epistola ad Timotheum +; scan1.txt:25898-25899 "Lectio Epistolae beati Pauli Apostoli / ad +; Timotheum. 1 Tim. 6, 11-16" -- see the header's UNDIFFERENTIATED INCIPITS +; note. +timothy_1.abbr = 1 Tim +; scan1.txt:25899, same line as the .full citation. +timothy_2.full = Epistola ad Timotheum +; Shared incipit -- see timothy_1.full's own citation, plus scan1.txt:31361 +; "Lectio Epistolae beati Pauli Apostoli / ad Timotheum. 2 Tim. 4, 1-8". +timothy_2.abbr = 2 Tim +; scan1.txt:31364, also 24808/25001/26136. +titus.full = Epistola ad Titum +; scan1.txt:6302-6303 "Lectio Epistolae beati Pauli Apostoli / ad Titum." +titus.abbr = Tit +; scan1.txt:5768 "Tit. 3, 4-7", also 6304/43057. +hebrews.full = Epistola ad Hebraeos +; scan1.txt:5850-5853 "Lectio Epistolae beati Pauli Apostoli / ad +; Hebraeos.". Note this is the CLEAN scan1.txt instance, deliberately not +; scan2.txt:58410's own "Hebreeos" OCR damage the sourcing note warns about. +hebrews.abbr = Hebr +; scan1.txt:6392 "Hebr. 5,", also 6788/10951. + +; --- Catholic epistles -------------------------------------------------- +james.full = Epistola beati Iacobi Apostoli +; scan1.txt:20348 "Lectio Epistolae beati Iacobi Apostoli.", also +; 20432/20509/34828/38918/40963/41197/45872/49193 -- no "ad X" destination +; to shorten to, so the attribution stays; see the header's own note on this +; pattern. +james.abbr = Iac +; No clean "Iac." locator was found (only a damaged "lac." one, scan1.txt +; near 20349, the lowercase-L-for-capital-I OCR fault the sourcing note +; warns about) -- this is a straightforward truncation of the sourced word +; "Iacobi" above, matching the 3-4 letter convention every other abbreviated +; form in this section actually attests (Gal, Col, Phil, Hebr, ...), not a +; separately-sourced locator. +peter_1.full = Epistola beati Petri Apostoli +; scan1.txt:20021 "Lectio Epistolae beati Petri Apostoli.", also +; 20080/20264/20324/20784/22128/27337/30003/31627 -- CORRECTS the sourcing +; note; see the header's UNDIFFERENTIATED INCIPITS note (shared with +; peter_2). +peter_1.abbr = 1 Petri +; scan1.txt:19984 "1 Petri 2, 9" (Ant. ad Communionem, Friday within the +; Easter octave) -- the Missal's own locators for both Peter epistles use +; the unabbreviated genitive "Petri", not a further-truncated "Pet." form +; (checked: no "1 Pet."/"2 Pet." instance in either scan). +peter_2.full = Epistola beati Petri Apostoli +; Shared incipit -- see peter_1.full's own citation, plus scan1.txt:34670 +; "Lectio Epistolae beati Petri Apostoli. / 2 Petri 1, 16-19" directly. +peter_2.abbr = 2 Petri +; scan1.txt:34671, same line as its own .full citation above. +john_1.full = Epistola beati Ioannis Apostoli +; scan1.txt:20162 "Lectio Epistolae beati Ioannis Apostoli.", also +; 21801/21961/26111/27522/33348/45129. +john_1.abbr = 1 Ioann +; scan1.txt:20163 "1 Ioann. 5, 4-10", also 32440. + +; --- Apocalypse ----------------------------------------------------------- +apocalypse.full = Liber Apocalypsis +; scan1.txt:6229 "Lectio libri Apocalypsis beati Ioannis / Apostoli.", also +; 27078/29761/37514/37749/39427/39816/42821/50569 -- attribution dropped, +; same as Acts/Romans above. +apocalypse.abbr = Apoc +; scan1.txt:6230 "Apoc. 14,", also 27049/27588. + +; --- Tradition targets ---------------------------------------------------- +; kings_1, kings_2, nehemiah, sirach, hosea, jonah, revelation +; (Colitur_citation.Book.tradition_targets, book.ml) are what +; `--sigla-tradition modern` maps ONTO -- the Vulgate data this file +; otherwise names never cites them directly (book.mli). This 1962 Missal is +; Vulgate-numbered throughout, so none of these MODERN-numbering ids could +; ever have a Latin incipit to source in the first place -- not a search +; gap, a category mismatch. All seven are UNSOURCED by construction; both +; forms fall back to Book.default_spelling, which for an id absent from +; book.ml's own spelling table (true of all seven -- they exist only in +; `tradition_targets`, never in `table`) is the bare id itself. This is what +; `test_every_book_named` (test/test_lang_coverage.ml) exists to hold in +; place: without an explicit row here, `--sigla-tradition modern` would +; render one of these bare ids straight into a citation. +; UNSOURCED (all seven rows below -- see this section's own header +; immediately above for why: a category mismatch, not a search gap). +kings_1.full = kings_1 +kings_1.abbr = kings_1 +kings_2.full = kings_2 +kings_2.abbr = kings_2 +nehemiah.full = nehemiah +nehemiah.abbr = nehemiah +sirach.full = sirach +sirach.abbr = sirach +hosea.full = hosea +hosea.abbr = hosea +jonah.full = jonah +jonah.abbr = jonah +revelation.full = revelation +revelation.abbr = revelation -- cgit v1.3 From 5638f25a6d51477f8c8417b0586b8a10f79ec8f0 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 20 Aug 2026 17:17:42 +0200 Subject: fix(lang): disambiguate the two Books of Kings in full mode Both kings_3 and kings_4 carried the full title "Liber Regum", so --sigla-book full rendered 3 Kings and 4 Kings identically and a reader could not tell which book a citation named. Seven citations in 2027 alone. The cause is real and now recorded rather than papered over: this Missal's incipit "Lectio libri Regum." is UNDIFFERENTIATED -- that exact unqualified phrase precedes both a "3 Reg." and a "4 Reg." locator in the same book -- so it is not a valid full title for either volume on its own. Only the numbered locator distinguishes them, and both "3 Reg" and "4 Reg" are independently attested in the scans. The full titles are therefore marked CONSTRUCTED, a third category beside sourced and UNSOURCED: both halves are transcribed, their combination is not. The numeral is written in Roman to match this project's own output convention ("Feria IV", "Hebdomada I"). Abbreviated and --raw output are unchanged. --- lang/la.ini | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'lang/la.ini') diff --git a/lang/la.ini b/lang/la.ini index 537f9a3..369d6b3 100644 --- a/lang/la.ini +++ b/lang/la.ini @@ -1888,14 +1888,20 @@ numbers.full = Liber Numeri ; Numeri." is clean and unambiguous. numbers.abbr = Num ; scan1.txt:9968 "Num. 20, 1, 3 et 6-13", same page as the .full citation. -kings_3.full = Liber Regum -; scan1.txt:8376/9116/10341 "Lectio libri Regum." -- see the header's own -; UNDIFFERENTIATED INCIPITS note: this exact phrase, unqualified, precedes -; both a "3 Reg." and a "4 Reg." locator elsewhere in the same Missal. +kings_3.full = Liber Regum III +; CONSTRUCTED, not transcribed -- both halves are sourced, their combination +; is not. The incipit "Lectio libri Regum." (scan1.txt:8376/9116/10341) is +; UNDIFFERENTIATED: that exact unqualified phrase precedes both a "3 Reg." +; and a "4 Reg." locator in this same Missal, so on its own it does not +; identify WHICH volume and is therefore not a valid full title for either. +; The volume numeral comes from the sourced locator (3 Reg / 4 Reg below), +; written as a Roman numeral to match this project's own output convention +; ("Feria IV", "Hebdomada I"). Bare "Liber Regum" was rejected: it rendered +; 3 Kings and 4 Kings identically under --sigla-book full, losing the book. kings_3.abbr = 3 Reg ; scan1.txt:8376 "3 Reg. 19, 3-8", also scan2.txt:11230/11671. -kings_4.full = Liber Regum -; Shared incipit -- see kings_3.full's own citation and the header note. +kings_4.full = Liber Regum IV +; CONSTRUCTED -- see kings_3.full's own note for the full reasoning. kings_4.abbr = 4 Reg ; scan1.txt:9668 "4 Reg. 5, 1-15", also scan1.txt:10636/9771. esdras_2.full = Liber Esdrae -- cgit v1.3 From 46ffa91fd4fcc2249cd097b3b3a639d37a7d592e Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 20 Aug 2026 17:33:26 +0200 Subject: fix(lang): stop internal book ids reaching output, and finish the docs Three defects, all found by running the documented examples rather than by reading code. All seven modern-numbering targets carried their own internal id as their Latin name (kings_1.full = kings_1), so --sigla-tradition modern printed "kings_1 19:3-8" -- leaking a key book.mli states is never shown to a reader. They now carry Vulgate-derived Latin names marked CONSTRUCTED: the 1962 Missal uses Vulgate numbering throughout, so it can contain no incipit for a book that exists only under a later convention. In Latin the modern tradition therefore only moves Kings and Esdras; Osee, Ionas, Ecclesiasticus and the Apocalypse keep their names either way, since modern numbering is a vernacular convention. The coverage test could not catch this. It compares a name against its KEY ("kings_1.full"), and "kings_1" differs from that, so the row passed. A second check now asserts no name IS its own id. The two are complementary: one catches a missing row, the other a row present but filled with the wrong thing. Mutation-proved. --help still claimed sigla settings were resolved "but not yet rendered", stale since the render wiring landed. colitur-config.5 documented none of the three settings even though config --show prints them. --- bin/main.ml | 7 +++--- lang/la.ini | 51 ++++++++++++++++++++++++++----------- man/colitur-config.5 | 63 ++++++++++++++++++++++++++++++++++++++++++++++ test/test_lang_coverage.ml | 28 +++++++++++++++++++++ 4 files changed, 132 insertions(+), 17 deletions(-) (limited to 'lang/la.ini') diff --git a/bin/main.ml b/bin/main.ml index 5ad3132..c76a082 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -1267,9 +1267,10 @@ naming: `abbr`), the same discipline as an unknown `--lang`; an unrecognised `--sigla-tradition` is not -- it degrades to the Vulgate with a stderr warning, because asking for a renumbering - is optional the way asking for a language is not. Settings - only, for now: this build resolves and reports them but does - not yet render a citation through them. + is optional the way asking for a language is not. `--raw` + bypasses all of it and emits each citation exactly as stored, + byte for byte, so it stays usable for diffing and does not + depend on the citation parser being correct. colitur lang --list which language files this build can find, and each one's own declared fallback, if any. diff --git a/lang/la.ini b/lang/la.ini index 369d6b3..3783482 100644 --- a/lang/la.ini +++ b/lang/la.ini @@ -2157,17 +2157,40 @@ apocalypse.abbr = Apoc ; render one of these bare ids straight into a citation. ; UNSOURCED (all seven rows below -- see this section's own header ; immediately above for why: a category mismatch, not a search gap). -kings_1.full = kings_1 -kings_1.abbr = kings_1 -kings_2.full = kings_2 -kings_2.abbr = kings_2 -nehemiah.full = nehemiah -nehemiah.abbr = nehemiah -sirach.full = sirach -sirach.abbr = sirach -hosea.full = hosea -hosea.abbr = hosea -jonah.full = jonah -jonah.abbr = jonah -revelation.full = revelation -revelation.abbr = revelation +; The seven MODERN-NUMBERING targets. All CONSTRUCTED, and necessarily so: +; the 1962 Missal uses Vulgate numbering throughout, so it can contain no +; incipit for a book that exists only under a later convention. Latin forms +; follow the Vulgate's own naming for the same physical book. +; +; They were previously set to the internal id ("kings_1.full = kings_1") by +; applying the UNSOURCED rule mechanically -- but that rule says to fall back +; to the spelling THE DATA USES, and these books are never cited by the data +; at all, so the fallback yielded the id. `--sigla-tradition modern` then +; printed "kings_1 19:3-8", leaking an internal key that book.mli states is +; never shown to a reader. +; +; Note that in LATIN the modern tradition only really moves Kings and Esdras: +; Osee, Ionas, Ecclesiasticus and the Apocalypse keep their Vulgate names, so +; those four map to an identical rendering. That is correct, not a no-op bug +; -- modern numbering is a vernacular convention, and these files show it. +kings_1.full = Liber Regum I +; CONSTRUCTED -- same reasoning as kings_3.full above, one volume lower. +kings_1.abbr = 1 Reg +kings_2.full = Liber Regum II +; CONSTRUCTED. +kings_2.abbr = 2 Reg +nehemiah.full = Liber Nehemiae +; CONSTRUCTED. The Vulgate calls this book 2 Esdras; see esdras_2 above. +nehemiah.abbr = Neh +sirach.full = Liber Ecclesiastici +; CONSTRUCTED. Same book as ecclesiasticus above, under its modern name. +sirach.abbr = Sir +hosea.full = Osee Propheta +; CONSTRUCTED. Identical to osee above -- see the note at the top of this block. +hosea.abbr = Os +jonah.full = Ionas Propheta +; CONSTRUCTED. Identical to jonas above. +jonah.abbr = Ion +revelation.full = Apocalypsis +; CONSTRUCTED. Identical to apocalypse above. +revelation.abbr = Apoc diff --git a/man/colitur-config.5 b/man/colitur-config.5 index 8f21028..6b3a574 100644 --- a/man/colitur-config.5 +++ b/man/colitur-config.5 @@ -181,6 +181,69 @@ accepts it. Relevant only to which requires a format either from this setting or from .BR \-\-format ; no default. +.TP +.B sigla_style +Which citation STYLE to render book names and punctuation with: a language +code, or a path to a file carrying a +.B [sigla] +section. Defaults to the resolved +.IR lang , +so a booklet's citations follow its own language unless told otherwise. +See +.BR colitur (1)'s +.B SIGLA +section for the five style settings. +.TP +.B sigla_book +.BR full " or " abbr . +Overrides the selected style's own +.B book +setting. Default +.BR abbr , +giving +.B "Luc. 5:12\-14" +rather than +.BR "Evangelium secundum Lucam 5:12\-14" . +An unrecognised value is a hard error, the same discipline as an unknown +.BR \-\-lang . +.TP +.B sigla_tradition +A section name in +.IR lang/traditions.ini , +deciding which book a reference DENOTES rather than what it is called. +Default +.BR vulgate , +the identity \(em colitur never renumbers unless asked. With +.B modern +the Vulgate's own +.B "3 Kings 19:3\-8" +renders as +.B "1 Reg 19:3\-8" +in Latin, or +.B "1 Kgs 19:3\-8" +under +.BR "\-\-lang en" . +In Latin the modern tradition only really moves Kings and Esdras: Osee, +Ionas, Ecclesiasticus and the Apocalypse keep their Vulgate names either +way, because modern numbering is a vernacular convention. +Unlike +.IR sigla_book , +an unrecognised value is NOT fatal: it warns on stderr and falls back to +.BR vulgate , +because asking for a renumbering is optional the way asking for a language +is not. +.PP +Naming and renumbering are deliberately separate mechanisms. +.I sigla_style +selects what a book is CALLED, which varies by language; +.I sigla_tradition +selects which book a reference DENOTES, which does not \(em "modern +numbering" is the same decision in Latin, Polish and English. Conflating +them is how a citation ends up naming the wrong book. +.PP +None of these affect +.BR \-\-raw , +which emits every citation exactly as stored, byte for byte. .SH UNKNOWN KEYS AND SECTIONS A key inside .B [defaults] diff --git a/test/test_lang_coverage.ml b/test/test_lang_coverage.ml index b2d32a4..0271a59 100644 --- a/test/test_lang_coverage.ml +++ b/test/test_lang_coverage.ml @@ -119,6 +119,32 @@ let test_every_book_named () = in Alcotest.(check (list string)) "every book named, both forms" [] missing +(* A name must not BE the internal id. The check above compares the value + against the KEY ("kings_1.full"), so a row reading `kings_1.full = kings_1` + passes it -- the two strings differ. That is exactly what shipped: all seven + tradition targets carried their own id as their name, and + `--sigla-tradition modern` printed "kings_1 19:3-8", leaking a key that + book.mli states is never shown to a reader. + + The two checks are complementary and neither subsumes the other: that one + catches a MISSING row, this one catches a row present but filled with the + wrong thing. *) +let test_no_book_name_is_an_internal_id () = + let la = la () in + let leaked = + List.concat_map + (fun id -> + let n = Colitur_citation.Book.to_string id in + List.filter_map + (fun form -> + let v = L.bible la (n ^ "." ^ form) in + if v = n then Some (n ^ "." ^ form) else None) + [ "full"; "abbr" ]) + Colitur_citation.Book.all + in + Alcotest.(check (list string)) "no book name is its own internal id" [] + leaked + (* lang/en.ini is DELIBERATELY partial (see its own header note): it declares [meta] fallback = la, so a slug it does not carry itself should still resolve through the chain to la.ini's name rather than degrade to the bare @@ -161,4 +187,6 @@ let suite = Alcotest.test_case "vocabularies complete" `Quick test_vocabularies_are_complete; Alcotest.test_case "every rite has a Latin name" `Quick test_every_rite_has_a_latin_name; Alcotest.test_case "every book named, both forms" `Quick test_every_book_named; + Alcotest.test_case "no book name is an internal id" `Quick + test_no_book_name_is_an_internal_id; Alcotest.test_case "en.ini falls back to Latin" `Quick test_en_falls_back_to_latin ] ) -- cgit v1.3 From 1da70dc7ac03fe33fb92b172a0e26932764170d6 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Thu, 20 Aug 2026 19:03:02 +0200 Subject: fix(citation): close the final review's blocking findings The branch was RED and reported green. `dune test` exited 1: test/cli.t pinned the pre-fix output `kings_1 19:3-8`, which the previous commit had already fixed to `1 Reg 19:3-8`. The gate command piped dune through `tail`, so it reported tail's exit status, and cram prints its diff BEFORE the alcotest summary, so the two lines shown were the passing ones. Verify with `dune test; echo $?`, never through a pipe. A style file's own `book` key was unreachable. sigla_book resolved against a hardcoded "abbr" and the result was applied unconditionally, so the documented `[sigla] book = full` could never win. Render gains book_string, and the style's own value is now the default that a flag or config overrides. The unit test pinned style_of_fields correctly while the wiring defeated it. `lang --check` filtered the reference set to the celebration prefix, so a file with no [bible] section at all reported a clean bill of health -- contradicting both the reason the keys change was made and lang.ml's own comment. It now reports missing book names too. The token test missed a FOURTH citation-bearing file: adjustments.sexp writes citations as `Set_citation`, not `(reference ...)`. Its 16 citations all parse, so nothing was broken, but nothing was checking. The first attempt at this fix read the file and extracted NOTHING -- the marker stopped before the opening quote, so every payload was the part label -- which is recorded in the code rather than left as a trap. Also: colitur-config(5) claimed a trailing period the data does not carry, and two la.ini scan quotes silently corrected OCR damage ("Ionae 3, I - I O", "Epistolse") while presenting themselves as verbatim. Both are now marked as corrections. --- bin/main.ml | 31 ++++++++++++++++++++++++++++++- lang/la.ini | 13 +++++++++++-- lib/citation/render.ml | 1 + lib/citation/render.mli | 10 ++++++++++ man/colitur-config.5 | 2 +- test/cli.t | 23 +++++++++++++++-------- test/test_citation.ml | 32 ++++++++++++++++++++++++++------ 7 files changed, 94 insertions(+), 18 deletions(-) (limited to 'lang/la.ini') diff --git a/bin/main.ml b/bin/main.ml index c76a082..1207b1d 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -780,7 +780,11 @@ let load_sigla ~raw ~lang_t ~sigla_style_flag ~sigla_book_flag ~sigla_tradition_ in let sigla_book_value, _ = Colitur_naming.Config.resolve ~flag:sigla_book_flag - ~config:(Colitur_naming.Config.sigla_book config) ~default:"abbr" + ~config:(Colitur_naming.Config.sigla_book config) + (* The STYLE's own [book] key is the default, so a style file can + set it and a flag/config still overrides. A hardcoded "abbr" + here made the documented [sigla] book key unreachable. *) + ~default:(Colitur_citation.Render.book_string style) in let book_form = match sigla_book_value with @@ -1870,11 +1874,36 @@ let lang_check path = in let missing = List.filter (fun s -> not (List.mem s have)) known in let unknown = List.filter (fun s -> not (List.mem s known)) have in + (* Book names are checked the same way, and separately. Without + this the reference set gained a [bible] half that nothing ever + consulted: a file with [bible] entirely absent reported a clean + bill of health while every citation silently fell back to the + data's own Latin spelling. A miss is the TOTAL-lookup contract's + own signature -- [Lang.bible] returns the KEY when there is no + entry -- so equality with the key IS the test. *) + let missing_books = + List.concat_map + (fun id -> + let n = Colitur_citation.Book.to_string id in + List.filter_map + (fun form -> + let key = n ^ "." ^ form in + if Colitur_naming.Lang.bible t key = key then Some key + else None) + [ "full"; "abbr" ]) + Colitur_citation.Book.all + in List.iter (fun s -> Printf.printf "missing: %s\n" s) (List.sort compare missing); + List.iter (fun s -> Printf.printf "missing book: %s\n" s) + (List.sort compare missing_books); List.iter (fun s -> Printf.printf "unknown slug: %s\n" s) (List.sort compare unknown); + let books_total = 2 * List.length Colitur_citation.Book.all in Printf.printf "%s: %d of %d celebrations named, %d missing, %d unknown\n" path (List.length known - List.length missing) (List.length known) (List.length missing) (List.length unknown); + Printf.printf "%s: %d of %d book names, %d missing\n" path + (books_total - List.length missing_books) books_total + (List.length missing_books); if unknown <> [] then exit 1) (* `colitur config --show` -- each effective setting, its resolved value, diff --git a/lang/la.ini b/lang/la.ini index 3783482..821acff 100644 --- a/lang/la.ini +++ b/lang/la.ini @@ -1997,7 +1997,12 @@ jonas.full = Ionas Propheta ; scan1.txt:11021 "Lectio Ionae Prophetae." -- CORRECTS the sourcing note ; (genitive "Ionae" -> nominative "Ionas"). jonas.abbr = Ionae -; scan1.txt:11022 "Ionae 3, 1-10", same page as the .full citation -- the +; scan1.txt:11022 -- OCR-NORMALISED, not verbatim: the line actually reads +; "Ionae 3, I - I O", the scanner having read the digits 1 and 0 as capital +; letter I and letter O. The reading is unambiguous in context (Jonas 3 has +; 10 verses and the pericope below runs to verse 10), but the quote is a +; correction, not a transcription, and is marked so rather than presented as +; if the page said it. Same page as the .full citation -- the ; Missal's own locator uses the genitive form directly, unabbreviated. malachi.full = Malachias Propheta ; scan1.txt:26697 "Lectio Malachiae Prophetae." -- CORRECTS the sourcing @@ -2101,7 +2106,11 @@ hebrews.abbr = Hebr ; --- Catholic epistles -------------------------------------------------- james.full = Epistola beati Iacobi Apostoli -; scan1.txt:20348 "Lectio Epistolae beati Iacobi Apostoli.", also +; scan1.txt:20348 -- OCR-NORMALISED, not verbatim: the line reads +; "Epistolse beati Iacobi Apostoli", the scanner having read the ligature ae +; as "se". The correction is certain (no Latin word "Epistolse" exists, and +; the same phrase is clean elsewhere), but it is a correction and is marked +; as one. Also ; 20432/20509/34828/38918/40963/41197/45872/49193 -- no "ad X" destination ; to shorten to, so the attribution stays; see the header's own note on this ; pattern. diff --git a/lib/citation/render.ml b/lib/citation/render.ml index c66a0ca..79aaa86 100644 --- a/lib/citation/render.ml +++ b/lib/citation/render.ml @@ -20,6 +20,7 @@ let default_style = let part_sep st = st.part_sep let range st = st.range let book_sep st = st.book_sep +let book_string st = match st.book with `Full -> "full" | `Abbr -> "abbr" (* Arabic -> Roman, for the {chapter_roman} placeholder. Lifted from [Colitur_render.View.roman_numeral], which prints "Hebdomada I" week diff --git a/lib/citation/render.mli b/lib/citation/render.mli index d741931..274900c 100644 --- a/lib/citation/render.mli +++ b/lib/citation/render.mli @@ -44,5 +44,15 @@ val range : style -> string [\textasciitilde{}]. *) val book_sep : style -> string +(** The style's own book form, as the string a config file would write + (["full"] or ["abbr"]). + + Exists so a caller can use the STYLE's value as the default when + resolving the [sigla_book] setting. Resolving against a hardcoded + ["abbr"] instead makes a style file's own [book] key unreachable -- + the value is always overwritten before it can apply -- which is what + shipped until this accessor existed. *) +val book_string : style -> string + val render : style -> names:(Book.id -> [ `Full | `Abbr ] -> string) -> Parse.t -> string diff --git a/man/colitur-config.5 b/man/colitur-config.5 index 6b3a574..0e242bf 100644 --- a/man/colitur-config.5 +++ b/man/colitur-config.5 @@ -201,7 +201,7 @@ Overrides the selected style's own setting. Default .BR abbr , giving -.B "Luc. 5:12\-14" +.B "Luc 5:12\-14" rather than .BR "Evangelium secundum Lucam 5:12\-14" . An unrecognised value is a hard error, the same discipline as an unknown diff --git a/test/cli.t b/test/cli.t index d9d8ec5..b44a256 100644 --- a/test/cli.t +++ b/test/cli.t @@ -1261,12 +1261,14 @@ slug the engine can produce over 2020-2045: $ colitur lang --check d.ini d.ini: 725 of 725 celebrations named, 0 missing, 0 unknown + d.ini: 104 of 104 book names, 0 missing `--check` reports what is MISSING (a real slug with no entry): $ printf '[meta]\nlang = zz\n[celebration]\nef-epiphany = Test\n' > partial.ini - $ colitur lang --check partial.ini | tail -1 + $ colitur lang --check partial.ini | tail -2 partial.ini: 1 of 725 celebrations named, 724 missing, 0 unknown + partial.ini: 0 of 104 book names, 104 missing `--check` REJECTS an unknown slug (exit 1), so a typo is visible rather than silently dead -- its author would otherwise never learn why the name they @@ -1431,15 +1433,20 @@ Latin-convention punctuation. The synthetic file below overrides only `--sigla-tradition` renumbers which book an id DENOTES (lang/traditions.ini), independently of style or naming -- `modern` maps `3 Kings` onto the id -`kings_1`. Task 10's `la.ini` now carries a `[bible]` row for `kings_1` (a -tradition target the Vulgate data never cites directly, book.mli), but only -its own bare id -- an honest UNSOURCED placeholder, not a name (la.ini's own -`[bible]` header note) -- so it still prints literally, now BY DESIGN rather -than by the row's absence, still a real, if plain, witness that the -tradition actually applied rather than a no-op: +`kings_1`, whose own Latin name la.ini marks CONSTRUCTED: the 1962 Missal +uses Vulgate numbering throughout, so it can contain no incipit for a book +that exists only under a later convention. In Latin the modern tradition +therefore only really moves Kings and Esdras -- Osee, Ionas, Ecclesiasticus +and the Apocalypse keep their Vulgate names either way, because modern +numbering is a vernacular convention: $ colitur readings 2027 --sigla-tradition modern | grep '^2027-02-17' - 2027-02-17 ef-lent-ember-wed | kings_1 19:3-8 | Matth 12:38-50 | Feria IV Quatuor Temporum Quadragesimae + 2027-02-17 ef-lent-ember-wed | 1 Reg 19:3-8 | Matth 12:38-50 | Feria IV Quatuor Temporum Quadragesimae + +Under an English file the same mapping shows its usual face: + + $ colitur readings 2027 --lang en --sigla-tradition modern | grep '^2027-02-17' + 2027-02-17 ef-lent-ember-wed | 1 Kgs 19:3-8 | Matt 12:38-50 | Lenten Ember Wednesday `table`/`render`, `emit` and `publish` accept the same three flags too -- smoke-tested for exit status alone here (a minimal inline template, the diff --git a/test/test_citation.ml b/test/test_citation.ml index 1efaa10..133553b 100644 --- a/test/test_citation.ml +++ b/test/test_citation.ml @@ -117,8 +117,7 @@ let starts_with_at content pos prefix = [Str]/regex -- a plain forward scan for the marker, then read to the closing quote. Mirrors the coordinator's own survey command (grep -oh over the reference marker, quote-delimited). *) -let references content = - let marker = "(reference \"" in +let references_with marker content = let mlen = String.length marker in let len = String.length content in let rec loop pos acc = @@ -151,14 +150,35 @@ let book_token r = let stop = if !i < len && r.[!i] = '.' then !i + 1 else !i in String.sub r 0 stop +(* A citation is written TWO ways in this project's data, and a survey that + knows only one of them silently under-reads the corpus: + (reference "Isa 60:1-6") -- lectionary/sanctoral/commons + (Set_citation First "Wis 7:7-14") -- adjustments.sexp, an overlay + Both markers are scanned below. *) +let references content = + (* Each marker must include the OPENING QUOTE. [references_with] returns + the text between the marker and the next '"', so a marker stopping at + "(Set_citation " yields "First " / "Gospel " -- the part label, never + the citation -- and every entry is then silently discarded. That was + this function's first version, and it read the file while extracting + nothing at all. *) + references_with "(reference \"" content + @ references_with "(Set_citation First \"" content + @ references_with "(Set_citation Gospel \"" content + let test_every_data_file_token_resolves () = (* The check whose absence caused fix round 1: the brief surveyed only the lectionary and missed 21 tokens, several common, living in - sanctoral.sexp and commons.sexp. Read all three files at test time and - re-derive the token set from them, rather than hardcoding a list, so - this keeps working when the data changes. *) + sanctoral.sexp and commons.sexp. + + adjustments.sexp was then missed AGAIN, by this very test, because it + writes citations as `Set_citation` rather than `(reference ...)` -- the + same "one file too few" shape twice over. All FOUR shipped files are + read here, and the token set is re-derived from them at test time + rather than hardcoded, so this keeps working when the data changes. *) let files = - [ "../data/ef/lectionary.sexp"; "../data/ef/sanctoral.sexp"; "../data/ef/commons.sexp" ] + [ "../data/ef/lectionary.sexp"; "../data/ef/sanctoral.sexp"; + "../data/ef/commons.sexp"; "../data/ef/adjustments.sexp" ] in let tokens = files -- cgit v1.3