<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/tools/dune, branch v0.10.1</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.10.1</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.10.1'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-19T13:01:18Z</updated>
<entry>
<title>fix(tools): harden check_citations.py against its own self-poisoning bug</title>
<updated>2026-08-19T13:01:18Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T13:01:18Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=7f263a0ec9a91d1a036cfd22ed38354d06500b1d'/>
<id>urn:sha1:7f263a0ec9a91d1a036cfd22ed38354d06500b1d</id>
<content type='text'>
Reproduced the defect: reintroducing the exact historical citation bug
(pointing class-1's citation back at LT.txt:12459, the value a prior
fix round corrected away from) made the tool report "147 citations
checked, 0 look wrong". The mechanism was that the corrective comment
documenting the old bug quotes the wrong historical value, and the
checker pooled every quoted phrase from the whole surrounding comment
block, so citing the wrong line matched the comment explaining why it
was wrong.

Four changes:

1. The word pool for a citation is now scoped to the entry(ies) it is
   attached to only -- never to quoted text elsewhere in the comment.
   This is the direct fix for the self-poisoning bug.
2. A citation whose pool has fewer than two distinctive words (Latin
   liturgical headings are short and stopword-heavy) cannot
   discriminate the right line from a wrong nearby one. Such a
   citation is now reported CANNOT VERIFY and fails the target,
   instead of silently passing.
3. The blanket +-2-line tolerance is gone. A bare "LT.txt:N" is
   checked at line N only; a heading that genuinely wraps must say so
   explicitly as "LT.txt:N-M". The allowance moves into the data,
   where it is visible.
4. The tool gets its own test suite, tools/test_check_citations.py,
   with a synthetic fixture covering: a correct citation, off-by-one
   and off-by-three mismatches, an explicit wrap range, a degenerate
   pool, a PATTERN-marked entry with no citation, and a dedicated
   regression test for the self-poisoning case itself. Wired into
   `dune test` via a new (rule (alias runtest) ...) in tools/dune (a
   plain (test ...) stanza cannot run a Python script), so it runs
   with the rest of the suite, not only as a `make` target.

Added a --file/--lt-file override to check_citations.py so the tool
(and its own tests) can point at a fixture without touching the real
lang/la.ini or docs/research/LT.txt. Confirmed the "SKIPPED, exit 0"
behaviour for a missing docs/research/LT.txt is unchanged.

tools/__pycache__/ (a stray artefact of this script, previously
untracked and ungitignored) is now in .gitignore.

Measured against the current lang/la.ini (another task is still
landing its sanctoral entries on this branch): 15 of 275 citations now
look wrong and 42 more cannot be verified, both far above the 0 the
unhardened tool reported. Not fixed here -- the data pass is separate,
once the sanctoral entries land.
</content>
</entry>
<entry>
<title>test(differential): fix round 1 -- Holy Week, Lent Ember, RG 69</title>
<updated>2026-08-15T01:40:19Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-15T01:40:19Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=b0ff86ae552b90613be21c52433f4180deba7758'/>
<id>urn:sha1:b0ff86ae552b90613be21c52433f4180deba7758</id>
<content type='text'>
Two Critical findings, both real: Holy Week (including the entire Sacred
Triduum) was reading Passion Week's Masses -- the original colitur_keys
widened lectio's single, conflated ini section into both weeks instead of
Passion week alone. Narrowed to Passion week only; Holy Week's own four
cleanest days (Monday, Tuesday, Thursday, Saturday) are hand-authored
directly from the Missal, verified twice against both scans (C23); Holy
Wednesday and Good Friday are genuinely multi-lesson liturgies with no
single Epistle slot and are deliberately left unanswered, not guessed (C24).

The Lenten Ember days were still dead keys: Temporal_ef computes
ef-lent-ember-{wed,fri,sat}, lectio's ini names the same data
ef-lent-1-{wednesday,friday,saturday}, and colitur_keys never translated
it -- both engines independently fell through to the same wrong ferial
answer, so even the differential stayed green (C22, a genuine lectio bug
recorded for upstream). Fixed the instance and the class: colitur_keys
gained the rename, and tools/bootstrap_lectionary.ml gained
assert_reachable, sweeping Rite_ef.Temporal_ef.temporal at generation time
so a translation table entry naming a slug colitur never computes dies
loudly instead of shipping silently, plus an informational log of every
real slug with no entry at all.

C21 ("colitur's step 3 cannot reach a correct answer for the fixed
Christmastide slugs") is retired, superseded rather than merely patched:
the Nativity-Octave days now have their own direct Missal formulary
(Tit. 3,4-7/Luc. 2,15-20, "Diebus infra octavam Nativitatis Domini"),
resolved at step 2, not step 3 at all. That surfaced a real RG 69 gap
underneath it: a Sunday landing 26-31 December should keep its own Office,
not the fixed weekday placeholder, which Temporal_ef does not currently
distinguish. C6's verdict is re-opened (open, not colitur) for the 19 of
its 138 rows where this applies directly, and a new entry C25 (57 rows)
records the same gap propagating one hop further through step 3 into Holy
Name week. Both are out of this task's own scope -- a behaviour change to
a shared, multi-round-reviewed kernel-adjacent function -- and recorded,
not fixed, per the coordinator's own instruction.

C6's own note is rewritten in full rather than layered with another
correction; C18's stale trailing count is fixed to match its own pin; the
Vigil-misapplication risk flagged as a Minor closed itself once the
Nativity-Octave fix landed, confirmed by inspection rather than assumed.

dune test: 358/358. COLITUR_EXHAUSTIVE_SWEEP=1 dune test --force: 359/359.
</content>
</entry>
<entry>
<title>data(ef): bootstrap the temporal lectionary from lectio</title>
<updated>2026-08-14T15:05:51Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T15:05:51Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=6f5814ccdbc839b75c3e6de95a8ba9a755bc6ece'/>
<id>urn:sha1:6f5814ccdbc839b75c3e6de95a8ba9a755bc6ece</id>
<content type='text'>
119 entries, Epistle + Gospel only. The generator refuses a section carrying
exactly one of the two: an Epistle without a Gospel is malformed and wants
investigating, not shipping. SHA-256 of the source INI is in the provenance
header, as with sanctoral.sexp.
</content>
</entry>
<entry>
<title>data(ef): bootstrap the 1962 sanctoral from lectio</title>
<updated>2026-08-11T22:05:57Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T22:05:57Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=4624441d0bc9c1f28dea54606ab7999041d4b323'/>
<id>urn:sha1:4624441d0bc9c1f28dea54606ab7999041d4b323</id>
<content type='text'>
Convert lectio's tridentine-calendar.ini (322 entries) into
data/ef/sanctoral.sexp via a validating OCaml converter, tools/
bootstrap_sanctoral.ml, rather than a hand-written script: every field is
built through Slug.of_string, Colour.of_string and Vocab_ef.rank_of_string,
so the emitted sexp is valid by construction.

Two conversion decisions, both documented rather than buried:
- subject defaults to Subject.Saint, overriding Celebration.make's kernel
  default of Subject.Temporal, for the 316 entries with no explicit class;
- rank = commemoration maps to status = Commemoration_only with an inferred
  Class3 (not a citation -- it is what the 1960 reform reduced most simple
  feasts from), recorded as an open item in the rules register for the
  oracle to adjudicate.

Every celebration is tagged layer = Precedence_ef.universal_layer, the
provenance id RG 91's band classifier reads to tell the universal calendar
from proper/indult data.

The generated file carries a provenance header: source path, its SHA-256,
and the UTC conversion date, so re-bootstrapping against a newer lectio is
reproducible and diffable. Output is byte-identical across runs.

test/test_sanctoral_ef.ml loads the file through Layer.load and checks the
counts independently derived from the source INI (322 entries, 114
Commemoration_only, 12 Class1, no Subject.Temporal, every date resolves in
a leap year), plus two named spot-checks against the INI's own text -- one
entry with an explicit class field, one commemoration -- so a passing count
cannot hide the wrong 322 entries having been converted.
</content>
</entry>
</feed>
