<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/lib/citation/render.ml, branch main</title>
<subtitle>deterministic OCaml engine to compute and validate liturgical calendars for multiple rites, template-driven output to year 9999</subtitle>
<id>https://git.labunix.xyz/colitur.git/atom?h=main</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-26T21:53:58Z</updated>
<entry>
<title>fix(citation): represent chapter-crossing verse ranges (W4)</title>
<updated>2026-08-26T21:53:58Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-26T21:53:49Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=90584d87e763789808329847c46dbaa8e22dca47'/>
<id>urn:sha1:90584d87e763789808329847c46dbaa8e22dca47</id>
<content type='text'>
Parse.verse_range's [last] endpoint gains an optional chapter
(Parse.verse_end: { chapter : int option; verse : verse_num }), so a
hyphen range whose two endpoints lie in different chapters
("1 John 1:5-2:2") can be represented at all. Rejected: a bare
[int option] living alongside [last] as a second field on
verse_range -- that would let 'a chapter with no verse' exist as a
constructible value.

parse_part now splits a part's leading "chapter:" at the FIRST
colon only (not every colon), so the verses side can itself carry a
second colon from a crossing range. parse_range detects a crossing
by checking whether the range's right-hand side contains ':', and
skips the same-chapter descending-range guard for that case (a later
chapter is always "ahead", whatever its own verse numbers are).
Handles the compound shape too -- a crossing range followed by
further, same-chapter verse references in the same comma list
("Matthew 9:35-10:1,5a,6-8") -- since those trailing pieces parse as
ordinary bare verses/ranges, unaffected by the preceding crossing.

Render's one_range renders a crossing [last] through the same
chapter_verse template one_part already uses for the part's own
leading "chapter:verses", so a style that reconfigures the
chapter/verse separator renders a crossing endpoint in that same
convention rather than a hardcoded ':'.

This closes the W4 known-wrong: 41 (now 49, after an intervening
Second-reading extraction) of the OF lectionary's citations printed
unconverted, every one this exact shape. test_citation_coverage_of.ml's
pinned residual is now empty and asserted exactly, over the full
1725-field data/of/lectionary.sexp population, including the round-trip
check (parse -&gt; render -&gt; parse structural equality). test_citation.ml
gains direct parse-suite cases for the basic crossing, the compound
shape, a mid-list crossing, a crossing with a sub-verse letter, and a
malformed-crossing rejection.

data/of/lectionary.sexp is regenerated via its own generator
(tools/bootstrap_lectionary_of.ml, whose own embedded header text is
updated to match); only comment lines change, confirmed by diff --
no lectionary entry differs. test_lectionary_of.ml's whole-file
SHA-256 pin is updated to match.

EF is unaffected: data/ef/ is untouched since v1.0.0, and a direct
byte comparison of `colitur day`/`colitur readings` for 2026, 1583
and 9999 against a git-worktree build of 1c0137d is identical on all
six outputs.
</content>
</entry>
<entry>
<title>fix(citation): recognise English-canonical OF books, verse sub-letters</title>
<updated>2026-08-26T11:30:02Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-26T11:30:02Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=9cc763c169a6ce4ebbdbed506c5eb2dad1f9f3c1'/>
<id>urn:sha1:9cc763c169a6ce4ebbdbed506c5eb2dad1f9f3c1</id>
<content type='text'>
35% of OF citation fields (259/730 on colitur readings --rite of 2026)
printed unconverted -- 1 John renders on 2 January but not 3 January.
Two independent causes, both in the citation/siglum path, neither in
the OF data itself:

1. Book.table only ever surveyed the three EF citation-bearing files,
   so 345 references citing a book no EF file happens to use (Job,
   Ruth, Judges, 1/2 Samuel, 1/2 Chronicles, 1/2 Maccabees, Baruch,
   Ecclesiastes, Habakkuk, Haggai, Nahum, Zechariah, Zephaniah,
   Deuteronomy, Amos, Micah, Lamentations, Ezra, Joshua, 2/3 John,
   Jude, Philemon, plus "Isaiah"/"Jeremiah"/"Ezekiel"/"Malachi"/"Mat"/
   "The Acts"/"Tobit"/"Song of Solomon" spelling variants of books EF
   already knows) failed as "unknown book". Added as a new, separate
   of_lectionary_table rather than folded into the EF-surveyed table:
   none of these 25 new books is attested in the EF's own scans, and
   lang/la.ini's own header refuses to fabricate an uncited Latin
   title, so they are resolvable (parse + render, falling back to
   their own English spelling) but deliberately excluded from Book.all
   -- test_lang_coverage.ml's la.ini-completeness promise is preserved
   exactly for the ids it already covered, not silently weakened.

2. Parse's grammar could not read a verse number carrying a lectionary
   sub-verse letter ("11a", "1bcde") at all -- the dominant remaining
   failure shape once (1) was fixed. verse_range now carries a
   verse_num { n; suffix } on each boundary, PRESERVED through
   rendering rather than dropped (dropping would silently lose real
   precision the source text carries). Chapter numbers are untouched
   (nothing in the data ever attaches a letter to one).

A third, subtler bug surfaced by (1): registering "jude"/"philemon"/
"2 John"/"3 John" exposed Parse's existing "leading comma-number is a
chapter" heuristic misreading a single-chapter book's bare verse list
("Jude 17,20b-25") as chapter 17 -- a wrong PARSE, worse than the
previous safe "unknown book" failure. Book.is_single_chapter now tells
Parse to skip that heuristic for the four one-chapter books and default
to chapter 1.

Residual, honestly enumerated rather than forced to zero: 41 distinct
references (of 1540) are hyphenated ranges crossing a chapter boundary
("2:29-3:6") -- a Parse.t shape verse_range/part do not represent, a
type restructuring deliberately not attempted this task. Pinned exactly
by the new test_citation_coverage_of.ml, both directions (a new failure
or one of these 41 starting to convert both go red), and disclosed in
data/of/lectionary.sexp's own regenerated provenance header (tools/
bootstrap_lectionary_of.ml now runs the same parser at generation time
and names the count and the set).

Verified EF-unaffected: git diff v1.0.0..HEAD -- lib/kernel/
lib/rites/rite_ef/ data/ef/ is empty, and `colitur day`/`readings`
output for 2027 is byte-identical against the pre-fix binary.
</content>
</entry>
<entry>
<title>fix(citation): close the final review's blocking findings</title>
<updated>2026-08-20T17:03:02Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T17:03:02Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=1da70dc7ac03fe33fb92b172a0e26932764170d6'/>
<id>urn:sha1:1da70dc7ac03fe33fb92b172a0e26932764170d6</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>feat(citation): render a parsed citation in a configurable style</title>
<updated>2026-08-20T13:09:49Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T13:09:49Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=a2cbb6b85e79fbc59b0879362c0f853757d51c07'/>
<id>urn:sha1:a2cbb6b85e79fbc59b0879362c0f853757d51c07</id>
<content type='text'>
A style is a set of format strings, so punctuation convention is data.

Values are unquoted here rather than in Overlay_ini: that parser trims
every value and is shared with overlays and [defaults], so teaching it
about quotes would change behaviour this feature has no business
changing.
</content>
</entry>
</feed>
