<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git, branch v0.6.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.6.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.6.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-18T11:24:48Z</updated>
<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: CHANGELOG entry for 0.6.0</title>
<updated>2026-08-18T11:23:36Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:23:36Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=5d3e201c21427ec54ff3d58bade04e40cb621ae9'/>
<id>urn:sha1:5d3e201c21427ec54ff3d58bade04e40cb621ae9</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>merge: overlay authoring ergonomics</title>
<updated>2026-08-18T11:20:50Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:20:50Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=e48fa4a2d315ac2b3832611ff48ed2e986e7b49e'/>
<id>urn:sha1:e48fa4a2d315ac2b3832611ff48ed2e986e7b49e</id>
<content type='text'>
Two mandatory fields made optional, parse errors that stop naming kernel
source files, and a feedback loop -- colitur check and colitur new-overlay --
for a file the test layers deliberately cannot vouch for.
</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>feat(overlay): default citations and layer, humanise parse errors</title>
<updated>2026-08-18T11:13:40Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T11:13:40Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=8d0ab547895460956e36b66b47a299b02a3474f0'/>
<id>urn:sha1:8d0ab547895460956e36b66b47a299b02a3474f0</id>
<content type='text'>
A user-supplied overlay is the only sexp this engine reads that a human writes
by hand, and two of Celebration.t's eight fields carry nothing such an author
can meaningfully supply: citations is always empty for a local feast, since
citations come from the rite's lectionary and never from calendar data, and
layer merely repeats the overlay file's own id.

Requiring both made the commonest first mistake -- omitting them -- fail with
'lib/kernel/celebration.ml.t_of_sexp: the following record elements were
undefined: citations layer', which names a source file the author will never
open and does not say what to write instead. A minimal local feast needed 12
lines, two of them noise.

Overlay.load now fills each field only where ABSENT, so an explicitly stated
value always wins: an overlay may legitimately name a layer different from its
own id, and defaulting must not silently overwrite that. A test pins both
directions.

Deliberately scoped to overlays. Layer.load, which reads the shipped
sanctoral, is untouched and stays strict -- that data is the project's own,
every field of it is asserted by tests, and a missing one there is a defect
rather than a convenience.

Parse failures also stop naming kernel source paths: the five prefixes that
actually reach a user are rewritten into the vocabulary of the file being
edited, and anything unrecognised passes through verbatim rather than being
reworded into something possibly wrong.
</content>
</entry>
<entry>
<title>feat(tools): export the lectio EF correction patch</title>
<updated>2026-08-18T10:57:18Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T10:57:18Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=084ff22997af208715656924d9fc23bf2ec10050'/>
<id>urn:sha1:084ff22997af208715656924d9fc23bf2ec10050</id>
<content type='text'>
colitur has been downstream of lectio since its data was bootstrapped from
it. These are the fields where that relationship should now invert: eight
changes, each annotated with the colitur allow-list entry carrying its rubric.

Deliberately a PATCH and not a regeneration. colitur carries 205 of the 327
Polish names lectio ships, so regenerating lectio's ini from colitur would
silently drop 122 of them; colitur also uses a different slug vocabulary for
Passion/Holy week and different Paschaltide week numbering. What colitur is
authoritative for is the adjudicated fields, and only those are emitted.

Comparing the two datasets field by field also caught a counting error in
colitur's own register that no assertion in this project was watching for:
six sanctoral entries carry subject = Lord, not the four recorded, because
the regex that counted them truncated on the two longest Polish names. The
RG 112(b) reachability measurement was re-run against all six and is
unchanged at 0/0; both docs are corrected.
</content>
</entry>
<entry>
<title>docs: record why RG 112(b)/(c)/(d-saint) are unbuilt</title>
<updated>2026-08-18T10:43:36Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T10:43:36Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=4d143d762713783d35b2b1d20f8a21d79884dafe'/>
<id>urn:sha1:4d143d762713783d35b2b1d20f8a21d79884dafe</id>
<content type='text'>
They have been carried as a bare 'unbuilt' for weeks. The reason is not
neglect, and it differs per clause -- now measured across 1583-9999 rather
than asserted.

(c) cannot fire in this architecture at all: Temporal_ef.temporal returns one
office per day, so two de Tempore candidates never coexist. Nothing to build.

(b) is already produced by RG 16(a), which is implemented: 0 days in either
direction, because a Lord feast takes an occurring Sunday's place with no
commemoration, and no Class1 Sunday shares a date with any of the four
Lord-subject entries.

(d)'s saint half has no candidate pair. Three apparent pairs are distinct
saints sharing a forename -- recorded so the false positive is not rediscovered
-- and the one real pair, agnes and agnes-secundo, is 7 days apart and
co-occurs 0 times.

(b) and (d) are data-unreachable rather than architecture-unreachable, so an
overlay can make either live. That is the entry_14_movable_band shape. Left as
an explicit open decision rather than silently resolved.
</content>
</entry>
<entry>
<title>docs: Rogation Wednesday is built, not blocked</title>
<updated>2026-08-18T10:41:26Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-18T10:41:26Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=7ee8aaf865203aa2134d0af661cb011f87650fd2'/>
<id>urn:sha1:7ee8aaf865203aa2134d0af661cb011f87650fd2</id>
<content type='text'>
CLAUDE.md still described it as architecturally blocked, and that claim was
being carried forward into task lists a release later. It was true when
written and was superseded by the very next task: the blocker was that no
(month, day) pair could anchor an Easter-relative trigger, and Date_spec
gained Easter_offset in v0.2.0. The entity has shipped since then as an
ordinary Add in adjustments.sexp -- 1 981 days across the domain carry it.

Also recorded the general lesson, since this cost a stale item twice: a
blocker phrased as an architectural impossibility was really a claim about
one type's expressiveness, and it dissolved when that type grew a
constructor.
</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>
</feed>
