<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/lang, branch v0.8.0</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=v0.8.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.8.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-20T17:03:02Z</updated>
<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>fix(lang): stop internal book ids reaching output, and finish the docs</title>
<updated>2026-08-20T15:33:26Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T15:33:26Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=46ffa91fd4fcc2249cd097b3b3a639d37a7d592e'/>
<id>urn:sha1:46ffa91fd4fcc2249cd097b3b3a639d37a7d592e</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>fix(lang): disambiguate the two Books of Kings in full mode</title>
<updated>2026-08-20T15:17:42Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T15:17:42Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=5638f25a6d51477f8c8417b0586b8a10f79ec8f0'/>
<id>urn:sha1:5638f25a6d51477f8c8417b0586b8a10f79ec8f0</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>feat(lang): Latin and English book names, and the shipped sigla styles</title>
<updated>2026-08-20T15:14:42Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T15:14:42Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=d68feb04f71c3dea3b59726e2ffca225d99eaa35'/>
<id>urn:sha1:d68feb04f71c3dea3b59726e2ffca225d99eaa35</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>fix(citation): complete the modern tradition, and test the shipped file</title>
<updated>2026-08-20T14:05:34Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T14:05:34Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=263d0d889073d214229aef9655d3db29540c0d12'/>
<id>urn:sha1:263d0d889073d214229aef9655d3db29540c0d12</id>
<content type='text'>
Apocalypse -&gt; Revelation was missing from [modern] while `revelation` was
already a declared tradition target, so the target existed with nothing
mapping onto it. Same Vulgate-to-modern shape as Ecclesiasticus -&gt; Sirach.

The injectivity test used to hand-copy the mapping table, which asserted
things about the copy and nothing about the artifact: a mapping added to
traditions.ini and forgotten in the test would have passed. It now reads
lang/traditions.ini and additionally asserts that [vulgate] is empty --
an entry there would silently renumber the DEFAULT, the one thing this
design promises never happens -- and that no declared target is left
unreachable.

Mutation-proved three ways: declaring an unused target, deleting a
mapping, and adding an entry to [vulgate] each redden it, the first two
naming the offending book.
</content>
</entry>
<entry>
<title>feat(lang): traditions.ini, and its install rule</title>
<updated>2026-08-20T14:01:39Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T14:01:39Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=9dfa264f2941f1ca38eff08b6157a94d332cffbd'/>
<id>urn:sha1:9dfa264f2941f1ca38eff08b6157a94d332cffbd</id>
<content type='text'>
Which book a reference denotes does not vary by language, so it lives in
its own file rather than in la.ini beside [weekday].

Six mappings, not four: Osee/Jonas are the same question as 3 Kings in
transliteration form.

The install rule is added in the same commit deliberately -- lang/ once
shipped without one, so the feature worked from the source tree and was
broken once installed.

bin/dune gains colitur_citation as a linked library, needed for the new
loader; lang_list's directory scan now excludes traditions.ini, which is
not a language file and does not parse as one.
</content>
</entry>
<entry>
<title>feat(render): Roman week numbers and date spans, as data</title>
<updated>2026-08-20T09:32:24Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T09:32:24Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=e2e56ac5af290b60ea01037e58e8bc00545c021c'/>
<id>urn:sha1:e2e56ac5af290b60ea01037e58e8bc00545c021c</id>
<content type='text'>
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).
</content>
</entry>
<entry>
<title>fix(naming): the rite prints its display name, not the internal id ef</title>
<updated>2026-08-20T08:39:47Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T08:39:47Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=1935f40c156563c134f87093bf6ec8da1cf4fc46'/>
<id>urn:sha1:1935f40c156563c134f87093bf6ec8da1cf4fc46</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>fix(install): ship lang/ so installed colitur resolves names</title>
<updated>2026-08-19T21:52:05Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T21:52:05Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=6994cb2008263678c183228c97dea673babb6f1e'/>
<id>urn:sha1:6994cb2008263678c183228c97dea673babb6f1e</id>
<content type='text'>
la.ini and en.ini (725 Latin/English liturgical names -- the entire
point of the naming-and-config work just merged) had no dune install
rule, so make install / dune install never copied them to
&lt;prefix&gt;/share/colitur/lang/. bin/main.ml's lang_dir() probes exactly
that installed path first, falling back to a build-tree layout that
also does not exist for an installed binary -- so every installed
user silently got raw slugs (ef-circumcision) and untranslated terms
(epistle/gospel) instead of resolved names, with no error at all.

The defect existed because nobody had run the installed binary from a
directory with no colitur source tree above it: dune exec and dune
test always resolve lang/ via the build tree, materialized as a side
effect of test/dune's cram deps, so every in-tree check stayed green
while the installed artifact was broken.

Add lang/dune, following schema/dune's exact pattern: an install
stanza placing la.ini and en.ini at &lt;prefix&gt;/share/colitur/lang/,
matching where bin/main.ml's lang_dir() already looked. No code
change was needed there -- only the missing install rule. Update
Makefile's install target help text and summary echo to mention lang
alongside ef/templates/schema.

Verified end to end: uninstalled, removed lang/dune, rebuilt and
reinstalled to reproduce the bug from an outside directory (~/tmp,
colitur table showed ef-circumcision/epistle); restored lang/dune,
reinstalled, and confirmed the same command now shows the resolved
Latin name and rubric terms, that ~/.local/share/colitur/lang/
contains both files, and that colitur emit --format csv shows a real
name in the name column. lang/la.ini and lang/en.ini are untouched.
Full suite: dune test --force, 495 tests, 0 failures.
</content>
</entry>
<entry>
<title>feat(lang): walk commemorations and transfers, name every slug they surface</title>
<updated>2026-08-19T20:26:33Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T20:26:33Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=7fd042f547582801d39e33718e1d3a6e7f2078b3'/>
<id>urn:sha1:7fd042f547582801d39e33718e1d3a6e7f2078b3</id>
<content type='text'>
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.
</content>
</entry>
</feed>
