<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/bin, branch v0.7.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.7.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.7.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-18T12:28:21Z</updated>
<entry>
<title>release: v0.7.0</title>
<updated>2026-08-18T12:28:21Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T12:28:21Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=e1f6ba9322012edb57171ac306045f54a83aaad5'/>
<id>urn:sha1:e1f6ba9322012edb57171ac306045f54a83aaad5</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(overlay): a flat INI front end, which verifies its own output</title>
<updated>2026-08-18T11:55:18Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:55:18Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=36daf47dde9b0c16dacef31163ea74effdd5e7f3'/>
<id>urn:sha1:36daf47dde9b0c16dacef31163ea74effdd5e7f3</id>
<content type='text'>
A convenience format for calendars that add a few local feasts and drop one
or two universal entries. Section names are slugs, a [overlay] section carries
the id, and status/subject/layer default so the common case -- an ordinary
local saint's feast -- says only what distinguishes it.

It is a FRONT DOOR, not a second data model. It parses to exactly the
Overlay.t the S-expression form parses to, and everything downstream is the
same code on the same values; a test asserts an INI overlay and its
hand-written sexp equivalent produce identical Overlay.t values. It is also
deliberately less expressive -- Add, Suppress and single-field Edit only --
and refuses Replace, multi-field edits and citation edits BY NAME rather than
dropping them silently. Anything it cannot say is a reason to write sexp.

Little of this is new machinery: tools/bootstrap_sanctoral.ml has parsed INI
and mapped it to celebrations since the sanctoral was bootstrapped from
lectio. The dates needed extending, since that mapping handled only MM-DD;
the flat forms are easter+N/easter-N and mon/day/nth, with nth negative to
count from the end.

`colitur convert` is a separate step rather than --overlay sniffing the
extension, so the author can read what their INI became. When a date form was
mistyped, "what did the engine actually get" is the question, and an invisible
transpile cannot answer it.

The conversion verifies its own output: the emitted text is parsed back with
the same function that loads an overlay and must equal what the INI denoted,
or nothing is written. That is the point of the module. A transpiler emitting
valid-but-wrong sexp is the failure a convenience format invites, and `colitur
check` could never catch it -- the output would parse cleanly and mean
something else.

That check was WRONG on the first attempt, in exactly the way it exists to
prevent. It re-serialised the parsed value instead of parsing the text being
returned, so it verified t -&gt; sexp -&gt; t, which is true by construction and
proves nothing. Found by mutation: corrupting the renderer to emit a different
overlay id sailed through and exited 0. It now parses the returned text, the
mutation is caught with exit 2, and two tests fail under it where none did
before.
</content>
</entry>
<entry>
<title>docs(man): colitur-overlay(5), the overlay format in full</title>
<updated>2026-08-18T11:33:41Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:33:41Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=150f8c550d2f9ebbac61d195eb342eb2b2ec6b95'/>
<id>urn:sha1:150f8c550d2f9ebbac61d195eb342eb2b2ec6b95</id>
<content type='text'>
The overlay format was documented in three partial places -- a paragraph in
colitur(1), a block in --help, and the comments inside the shipped example --
none of which was a reference. Someone writing a diocesan calendar had to
read all three and infer the rest.

Section 5 because an overlay is a thing a user AUTHORS rather than a command
they run: it belongs beside fstab(5), not in man1.

Covers every directive and every field edit, the six required fields and the
two optional ones, all three date specifications including the signed
Easter_offset and the negative nth, three worked examples, and the caveats.
The subject field gets a note explaining that it is not decoration -- it
decides whether a feast displaces an occurring Sunday under RG 16(a).

Two things it says that the code says and the old prose did not. There is no
Set_status and no Set_date among the field edits, deliberately: changing an
entry's status or its date makes it a different celebration rather than an
edited one, so Replace is the right directive and the change stays visible in
`colitur check` output. And a local feast missing from output has usually
LOST its day under the general rubrics rather than failed to load -- the
engine applies precedence to overlay entries exactly as to universal ones,
which is the first thing an author hits and was written down nowhere.

Writing it caught a documentation bug before it shipped: a first draft listed
a Set_status edit that does not exist and omitted Remove_name that does. Every
documented edit is now cross-checked against overlay.mli.

Linked from colitur(1)'s SEE ALSO and its OVERLAYS section, and from --help.
The Makefile installs it into man5, removes it on uninstall, and the man and
doc targets lint both pages.
</content>
</entry>
<entry>
<title>release: v0.6.0</title>
<updated>2026-08-18T11:24:48Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:24:48Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=f979aedcc8a11d2c5a175064526a6821e11c2c0c'/>
<id>urn:sha1:f979aedcc8a11d2c5a175064526a6821e11c2c0c</id>
<content type='text'>
</content>
</entry>
<entry>
<title>docs: point --help and the man page at the new overlay workflow</title>
<updated>2026-08-18T11:23:23Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:23:23Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=d727d07472172e3308ebd1706476a6bbf7ec1306'/>
<id>urn:sha1:d727d07472172e3308ebd1706476a6bbf7ec1306</id>
<content type='text'>
Both listed check and new-overlay among the commands but neither told a
reader how they fit together, which is the part that makes them useful. The
overlay sections now carry the four-step loop -- new-overlay, edit, check,
run -- and state what check does not do, since its name invites a stronger
reading than it earns.

Also documents what the format now permits: citations and layer optional, the
signed Easter_offset, the negative nth counting from the end of the month,
and the legal values of each of the six required fields, which previously
appeared only in the shipped example.
</content>
</entry>
<entry>
<title>feat(cli): colitur check and colitur new-overlay</title>
<updated>2026-08-18T11:16:53Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:16:53Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=49494c3aedf3f1b40c6ee36cb4de5615f097274c'/>
<id>urn:sha1:49494c3aedf3f1b40c6ee36cb4de5615f097274c</id>
<content type='text'>
Writing a local calendar had no feedback loop. An overlay is applied, not
validated -- that stays true, and the five test layers still cannot vouch for
a user's file -- but before this the only way to learn whether yours did what
you meant was to generate a year of output and grep for your own slug, and the
only way to see that a directive matched nothing was to notice a warning
scroll past among 365 lines.

`check` loads each overlay, applies it to the real shipped calendar, and
reports the directive counts, the slug each one targets, and any directive
that found no target. It exits 2 when a file fails to load or a directive
matched nothing, so it composes into a Makefile or a pre-commit hook rather
than merely being readable. It is applied to the SHIPPED calendar and not to
an empty layer on purpose: against an empty one every Suppress would fail
trivially and the check would be worthless.

It answers three narrow questions -- does the file parse, does every directive
find its target, what does the merged result contain. It does not validate a
calendar against the rubrics and cannot, and both the help text and the man
page say so rather than letting the name imply more than it does.

`new-overlay` prints a starter to stdout for redirection, rather than writing
a file where it likes. Every value in it is a placeholder that will appear in
`day` output if left unedited, so a half-finished overlay is visible rather
than silently inert, and it documents the three date shapes and the legal
values for each closed field inline.

load_ef_layer now returns its diagnostics instead of printing them: day and
readings still want them on stderr beside a year of output, while check wants
them on stdout, attributed to the overlay that produced them, and counted.
Printing at the source made the second impossible.

The cram test round-trips new-overlay through check rather than pinning the
template line by line -- editing its prose should not fail a test, but a
syntax error in it still must.
</content>
</entry>
<entry>
<title>release: v0.5.0</title>
<updated>2026-08-18T10:37:36Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T10:37:36Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=d5386c2121cfd5c6b73b573aa7db05b8ef21dff0'/>
<id>urn:sha1:d5386c2121cfd5c6b73b573aa7db05b8ef21dff0</id>
<content type='text'>
</content>
</entry>
<entry>
<title>release: v0.4.0</title>
<updated>2026-08-18T09:44:57Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T09:44:57Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=ca4287a6e99e14846f3560106156ef2b1c4b8cf2'/>
<id>urn:sha1:ca4287a6e99e14846f3560106156ef2b1c4b8cf2</id>
<content type='text'>
</content>
</entry>
<entry>
<title>release: v0.3.1</title>
<updated>2026-08-18T07:11:53Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T07:11:53Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=4fc8afc45a7371fdfe32f0683f7f0e26ab766faa'/>
<id>urn:sha1:4fc8afc45a7371fdfe32f0683f7f0e26ab766faa</id>
<content type='text'>
</content>
</entry>
<entry>
<title>test(cli): the 3 January pin is a BVM Saturday, not a feria</title>
<updated>2026-08-17T20:27:11Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-17T20:27:11Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=1fa4017a20dea1843e08afd257fc7798560659c4'/>
<id>urn:sha1:1fa4017a20dea1843e08afd257fc7798560659c4</id>
<content type='text'>
3 January 2026 is an unoccupied IV-class Saturday, so its office is Our
Lady's and now its Mass is too -- the second of the Missal's five, assigned
to Christmas through the Purification. The pin held the Christmastide
feria's readings, which is what colitur said before RG 309(a) was
implemented. Caught by make check on the 0.3.0 release, which is what that
gate is for.
</content>
</entry>
</feed>
