<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/dune, branch v1.0.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=v1.0.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v1.0.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-19T08:18:24Z</updated>
<entry>
<title>feat(cli): colitur publish -- the static tree</title>
<updated>2026-08-19T08:18:24Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-19T08:18:24Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=2760d43d695ba08fc33f65357590675707b6570d'/>
<id>urn:sha1:2760d43d695ba08fc33f65357590675707b6570d</id>
<content type='text'>
Writes ef/&lt;year&gt;.{json,csv,xml,ics}, one JSON per day, the schema and a
generated index. That tree is the API: any web server or git repo serves
it, and nothing runs at request time.

Deterministic: publishing twice is byte-identical, asserted in cli.t.
That is what makes publishing into a git repo safe -- the diff shows
only real change, and you review it before pushing.

Non-destructive: a manifest records exactly the files this tool wrote,
so --prune can only remove files a previous run created. A file you put
in the output directory yourself is never touched, with or without
--prune. Asserted in both directions.

Pruning a stale file also removes any directory it leaves empty behind
it (e.g. an old year's own ef/&lt;year&gt;/ tree), stopping at --out itself --
without this, a pruned year's own directory would survive empty and
test -d would still see it.

schema/day-v1.json is resolved the same prefix-relative way data/ef's
own sexp files are (installed vs build-tree, probed rather than
assumed), never from cwd, and a missing schema fails with one line on
stderr before anything is written rather than emitting an empty file.
Needed schema/day-v1.json wired into the root dune file's default alias
and into test/dune's cram deps -- unlike data/ and templates/, nothing
made dune mirror schema/ into the build tree before this.

unix is added to bin/dune's libraries for mkdir_p; it ships with the
compiler, so colitur.opam and dune-project are unchanged.
</content>
</entry>
<entry>
<title>kernel+ef: fix round 1 -- lectionary caller-supplied, not eager</title>
<updated>2026-08-14T22:36:43Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T22:36:43Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=f8d694d0cc19b71598e1ab64254efb069969f0a0'/>
<id>urn:sha1:f8d694d0cc19b71598e1ab64254efb069969f0a0</id>
<content type='text'>
Critical (coordinator review): a clean `dune build` produced a `colitur`
that died at startup on EVERY subcommand, including ones touching no
lectionary data at all. Root cause was two-fold: data/ef/lectionary.sexp was
never added to the root default-build alias (only materialised as a side
effect of the test suite's own deps, which is why every check in the prior
report passed), and Rite_ef.context loaded it as a module-init side effect
via failwith, undoing Lectionary.load's own "never raises" promise at a
point no caller could catch.

Fixed structurally: Rite_ef.context is now a function taking ~lectionary,
Lectionary_ef.readings takes ~lectionary, and neither touches the filesystem
any more -- the same caller-supplied discipline the sanctoral layer already
had, restoring rite_ef.mli's own pre-existing claim about it and leaving a
seam for a future diocesan lectionary overlay. bin/main.ml grows
load_ef_lectionary, a sibling of load_ef_layer, routed through the same
colitur: %s / exit 2 path. data/ef/lectionary.sexp added to the root default
alias. Every caller of Rite_ef.context updated to supply it.

Also: two new tests that genuinely distinguish chain step 1 from step 2
(19 March 2026, Joseph's own proper over a competing temporal entry; 13
January 2030, Holy Family reached only through the temporal slug, the
Baptism entirely absent) -- the prior two tests both survived swapping the
chain order. Both new pins verified directly against the real data. The
chain's own comment now states plainly that its warrant is lectio's observed
behaviour, not a confirmed Missal citation, per the rules register's own
open item.
</content>
</entry>
<entry>
<title>docs+test: small factual corrections (item 7, part 1)</title>
<updated>2026-08-12T08:40:12Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-12T08:40:12Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=ac569e859be08320e47909e496d6e5e8f6057da7'/>
<id>urn:sha1:ac569e859be08320e47909e496d6e5e8f6057da7</id>
<content type='text'>
Six independent, small corrections found during the final review:

- dune (workspace root): the comment said the stanza used "(:standard)"
  to preserve dune's default `default` alias target; the stanza actually
  spells that out explicitly via (alias_rec install). Comment now matches
  the code.
- test_validate.ml's test_easter_extremes asserted `List.length ys = 2`
  where an identity check was called for -- the comment already named
  1598 and 1666, but nothing confirmed extreme_years() found THOSE two
  rather than some other pair with the right cardinality. Now asserts the
  identities directly (the project's "cardinality where identity was
  required" vacuity flavour, per the review).
- test_oracle.ml and expected-divergences-missalemeum.sexp both claimed
  "one entry (M13) is [verdict open]" -- M11 is open too (its own verdict
  changed from colitur to open in fix round 1); both now say "two entries
  (M11 and M13)".
- expected-divergences-missalemeum.sexp's M2 note attributed `band` to
  temporal_ef.ml; `band` is precedence_ef.ml's own function.
- lib/kernel/precedence.mli documented `dropped`/`admit`'s physical-
  equality obligation nowhere -- it lived only in one rite's own module
  (Rite_ef.Precedence_ef.admit's doc comment), but this signature is what
  an author of the next rite actually reads. Added the obligation here,
  cross-referencing the EF instance as precedent, not the only source.
- README's opam install line omitted sexplib and ppx_sexp_conv (both in
  dune-project's own depends; `dune build` fails without them for a
  contributor following the README verbatim) and documented only
  `colitur easter`, though `temporal` and `day` both exist and are the
  more useful entry points. Fixed both.

No behaviour change: comment/doc/test-assertion corrections only (the
easter-extremes fix strengthens an assertion, it does not change what
passes). Verified byte-identical `colitur day` output across 1583, 1900,
1902, 2008, 2011, 2026, 2038, 9999. 259/259 tests green.
</content>
</entry>
<entry>
<title>build: materialise data/ef/*.sexp as part of the default build target</title>
<updated>2026-08-11T23:13:53Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T23:13:53Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=9725195fc4a1050ded151854f6653459dacc35b0'/>
<id>urn:sha1:9725195fc4a1050ded151854f6653459dacc35b0</id>
<content type='text'>
A genuinely clean rebuild -- rm -rf _build &amp;&amp; dune build &amp;&amp; dune exec
colitur -- day 2026 -- failed: nothing in the default build graph asked
for data/ef/sanctoral.sexp or adjustments.sexp, only test/dune's cram
stanza did (its own explicit deps), so dune build alone never
materialised them under _build/default/data/ef/, and colitur day
(bin/main.ml's data_dir, which reads them straight off the build tree)
failed to find them. dune build @runtest masked this entirely, and the
test suite could not have caught it on its own: the cram stanza supplies
its own deps regardless of whether anything else in the project needs
them.

Verified empirically that neither a plain (alias (name default) ...) in
data/ef/dune nor one in bin/dune is enough on its own -- bare 'dune
build' resolves to something narrower than either recursive alias
propagation would suggest. A root-level dune file's default alias,
explicitly depending on (alias_rec install) plus the two data files, is
what a genuinely clean rebuild actually needs.
</content>
</entry>
</feed>
