summaryrefslogtreecommitdiff
path: root/test/test_lang_coverage.ml
Commit message (Collapse)AuthorAgeFilesLines
* fix: audit findings — parser strictness, name ambiguity, and errorsLukasz Kasprzak2026-08-201-0/+118
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Found by auditing the shipped program rather than the diff. The parser accepted OCaml integer-literal syntax, so "Luke 1_1:5" read as chapter ELEVEN and "+5" as 5 -- a typo silently becoming a different chapter, reachable through any user overlay. Numbers are now plain digits and positive, and a descending range is rejected: 1:20-10 is always a transcription error. No shipped citation changed. FOUR PAIRS OF DIFFERENT BOOKS SHARED A FULL TITLE. 1 and 2 Corinthians both rendered "Epistola ad Corinthios", as did Thessalonians, Timothy and Peter -- 108 citations in 2027 alone that a reader cannot resolve to a book. This is the Kings defect fixed earlier and not generalised. The titles now carry their volume numeral, marked CONSTRUCTED, and a test asserts no two books share a name -- while allowing the case where two ids ARE the same book under different numbering, which a tradition relates. Spec section 8.5 is now delivered rather than merely recorded. Shipped styles did not re-parse their own output: 32 of 52 Latin abbreviations and 49 of 52 full titles failed, so a citation copied from colitur's own output into an overlay was passed through untouched and printed in the wrong language, silently. Every shipped name is registered as a spelling and split_book learned multi-word titles by longest-token match. Now 0 of 52 fail beyond the same-book aliases. Overlay errors were written for a compiler author: they named an OCaml source file the reader does not have and buried the useful token. The existing five-path rewriter is replaced by a generic one, applied to every load path rather than one, so "rank: is not one of the allowed values (at Class9)" replaces the raw Of_sexp_error dump. Also: the new-overlay scaffold documented citations and layer without showing them, and its comment implied the wrong nesting -- the single easiest thing to get wrong; error messages echoed whole file lines, copying an unrelated file's contents into stderr when a flag pointed at one; and config --show validated partway down its table, exiting 2 after writing five rows to stdout.
* fix(lang): stop internal book ids reaching output, and finish the docsLukasz Kasprzak2026-08-201-0/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* feat(lang): Latin and English book names, and the shipped sigla stylesLukasz Kasprzak2026-08-201-0/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* feat(render): Roman week numbers and date spans, as dataLukasz Kasprzak2026-08-201-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The ordo booklet's week header repeated the month name on every week even though the heading above already established it -- pure noise. Replace it with a Roman week number plus the span of dates the week covers, e.g. "Hebdomada I (Ian 1-2)", following the project's own rule that a presentation choice is data, not code. lang/{la,en}.ini gain a [month_abbr] section (three-letter month abbreviations); Lang.month_abbr follows Lang.month's exact shape, including the out-of-range and miss-returns-the-key contracts. The coverage test now fails loudly if an abbreviation goes missing, the same as [month] already does. Every week object in the view gains num_roman (Roman numeral, num stays as the arabic original -- Roman is a presentation choice, not an engine change), first_dom/last_dom (the day-of-month of the week's first and last IN-MONTH days, padding excluded), month_abbr (resolved through Lang.month_abbr), and single_day (true when the week holds exactly one in-month day). single_day is a flag, not a preformatted span string: the engine is logic-less and cannot itself decide between "Ian 1" and "Ian 1-2", so a template makes that call from the flag instead -- the same "shape the data, not the template" discipline in_month and last already follow. Weeks are built per month with padding only at the two ends, so a week's in-month days never cross a month boundary -- verified, not assumed: every week always has at least one real day since no month is shorter than a single week. Covered by three new View tests, including a real single-day-week witness (January 2027's own trailing week is a lone Sunday, the 31st).
* fix(naming): the rite prints its display name, not the internal id efLukasz Kasprzak2026-08-201-0/+13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The booklet's title page and running header read "Ordo 2027 . ef" -- an internal identifier reaching a reader, the same defect class the sanctoral/temporal slugs were already fixed for. lang/la.ini and lang/en.ini each gain a [rite] section mapping the rite id to a reader-facing name, sourced from the Missal's own title page (docs/research/LT.txt:6 "MISSALE ROMANUM", :15 "EDITIO TYPICA") plus the 1962 dating this project uses throughout (rules-register.md, CLAUDE.md) -- both cited in the ini comments, marked PATTERN since the phrase combines two title-page elements rather than quoting one verbatim heading. Lang.t gains a rite table/lookup (same total, miss-echoes-the-key contract as every other lookup here); View.of_days exposes rite_name alongside the existing rite field, which stays the stable key exactly as slug is kept beside name. Every shipped template that printed {{rite}} now prints {{rite_name}} instead. test_lang_coverage.ml gains a coverage assertion over every rite id the engine can emit -- one today -- so a second rite module (OF) landing without a matching [rite] entry fails loudly instead of printing its own bare id. Goldens regenerated through the Test_view.view_of path test_render_golden.ml itself uses (English with a Latin fallback), not the CLI (whose --lang default is plain Latin and would have pinned output the tests never produce). test/cli.t's own JSON prefix assertion updated to match: rite_name is a real new key in that generic view dump, sitting right after rite.
* feat(lang): walk commemorations and transfers, name every slug they surfaceLukasz Kasprzak2026-08-191-11/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | test_lang_coverage.ml's own coverage test used to walk only the OBSERVED day of each date (one Celebration.t per Liturgical_day.t). A liturgical day also carries a second stream of slugs -- commemorations (kept when the observed day does not fully displace a losing candidate, RG 108-111) and transfers (an impeded I/II-class feast moved to a later date, RG 96-98) -- and nothing here ever looked at them. The test asserted coverage of what it happened to WALK, not of what the engine can EMIT, so it passed green while the ordo booklet printed raw slugs ("Commemoratio canute-martyr", "Commemoratio maur-abbot", "Commemoratio peter"). test_lang_coverage.ml now walks observed, every entry in commemorations, transferred_in, and every entry in transferred_out. That extension turned up 120 slugs with no Latin name across 2020-2045, now added to lang/la.ini: 112 are data/ef/sanctoral.sexp companions the temporal-only walk never reached; 5 (barbara, commemoration-of-st-peter, commemoration-of-the-seven-sorrows, major-litanies, rogation-wednesday) are data/ef/adjustments.sexp's own hand-authored Add directives; 3 (ef-nativity-octave-day-2/3/4) are temporal days with no calendarium heading to transcribe, built by the same pattern days 5-7 already use. Seven of the sanctoral names are cited to docs/research/scan1.txt rather than LT.txt: the 2006 web-capture transcription silently drops several real commemorations that both photographic scans carry (donatus, romanus, eusebius-confessor, naboris-et-felicis, sts-gervasius-and-protasius, sts-felix-and-adauctus, and praxedis-virginis -- the last for a spurious ligature LT.txt introduces, "Praxedis" confirmed correct against both scans). The same 120 names, extracted verbatim from sanctoral.sexp's and adjustments.sexp's own English fields rather than retyped, are added to lang/en.ini. make check-citations: 400 LT.txt citations checked, 0 wrong, 0 malformed, 0 cannot verify. Teeth proved by deleting canute-martyr's own name (a Commemoration_only slug that can never be the observed day, only ever a commemoration) and confirming the coverage test fails naming exactly that slug, then restoring it.
* feat(lang): Latin sanctoral names, and EnglishLukasz Kasprzak2026-08-191-20/+51
| | | | | | | | | | | | | | | Sanctoral names are transcribed from the Missal's own calendarium and kept in the GENITIVE, as the Missal prints them -- noted in the file so nobody corrects them to the nominative. English reuses the 327 names already in data/ef/sanctoral.sexp rather than retyping them, and declares fallback = la, so an untranslated day in an English booklet shows Latin rather than a slug. The test asserts the FALLBACK works rather than that en.ini is exhaustive: that is what makes a partial translation shippable from its first line. Coverage now demands a name for every slug the engine can emit across 2020-2045, temporal and sanctoral alike.
* feat(lang): Latin temporal names from the MissalLukasz Kasprzak2026-08-191-0/+73
Every entry is transcribed from the 1962 Missal's own propers headings in docs/research/LT.txt and cites where it came from; names constructed by following a neighbouring pattern are marked as such, so a reader can tell transcription from inference. The coverage test is the point of this commit. It walks every day of 2020-2045 and fails naming any slug with no Latin name -- the test that would have caught the original defect, where a printed booklet said ef-septuagesima-sunday-2 because nothing asserted that names exist. The three Triduum names reuse the exact strings temporal_ef.ml already carries, so the engine and the language file cannot disagree.