<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git, branch main</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=main</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-09-03T19:13:38Z</updated>
<entry>
<title>Merge branch 'of-litcal-readings'</title>
<updated>2026-09-03T19:13:38Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-09-03T19:13:38Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=81a9df4bab615abdd8ef0e2fe7322219ce00ee6d'/>
<id>urn:sha1:81a9df4bab615abdd8ef0e2fe7322219ce00ee6d</id>
<content type='text'>
The OF's readings had never been validated against anything but the lineage
they arrived on. Pointing a second lineage at them found ten corrupt
references on the first run.
</content>
</entry>
<entry>
<title>chore: 1.2.1</title>
<updated>2026-09-03T19:13:33Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-09-03T19:13:33Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=fe136f0952284b9a339252926dfd4675c4a7c3c6'/>
<id>urn:sha1:fe136f0952284b9a339252926dfd4675c4a7c3c6</id>
<content type='text'>
Ten wrong scripture references reached users; nothing else about the engine
changed and no output format moved. A patch bump.

README's status line and test count follow the release, as they have to: the
count is 917 under the exhaustive sweep, not 916.
</content>
</entry>
<entry>
<title>fix(of): correct ten reading references, regenerated from lectio</title>
<updated>2026-09-02T10:54:07Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-09-02T10:54:07Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=b14a3078c1a4db87010f5df955442bf1e440e0ec'/>
<id>urn:sha1:b14a3078c1a4db87010f5df955442bf1e440e0ec</id>
<content type='text'>
Nine ended at verse 22 where the OLM ends them at 20; the tenth read
"Matthew 17:9a,10-135", a verse Matthew 17 does not have. Every one was in a
Year II entry, or in of-advent-2-saturday, which has no year cycle. Not one
Year I entry was affected -- that distribution is what made this a
transcription fault rather than ten independent slips.

Corrected upstream in lectio's own internal/caldata/of-lectionary.ini (its
suite green) and this file regenerated from it, per the header's own
instruction not to hand-edit a generated artifact. The diff is exactly the
source SHA-256 pin plus the ten references; both pins in test_lectionary_of.ml
move with it.

The Ordinary Time invariant added in the previous commit now asserts outright
rather than pinning six exceptions: in Ordinary Time the OF weekday Gospel does
not depend on the year of the cycle, so a -i/-ii pair whose Gospel differs is a
defect, and the expected violation set is empty. Mutation-tested against the
Year II entry alone -- an earlier attempt changed both halves of the pair and
passed for the wrong reason, which is worth knowing about this shape of test.

Measured: the 20-vs-22 divergence class against litcal goes 26 -&gt; 0 over the
twelve witnessed years. 917 tests, every year 1583-9999.

Also, L6/L7 (the Sacred Heart / John the Baptist tie at an equal Tabula entry)
gains the citation its note said did not exist. Tabula I.3 enumerates
"Sollemnitates Domini, beatae Mariae Virginis, et Sanctorum" -- an order, not a
bare category, and read that way it settles the tie against colitur's current
alphabetical answer. Recorded with its counter-argument (entry 4 marks its own
internal order with explicit lettering; entry 2's list cannot be an ordering at
all) and with what would settle it. Verdict stays open, behaviour unchanged.
</content>
</entry>
<entry>
<title>feat(cli): --help is one screen, not the whole manual</title>
<updated>2026-09-02T10:30:56Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-09-02T10:30:56Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=5dd14266f2609faadc3ec60077127a7ef7e8ac8b'/>
<id>urn:sha1:5dd14266f2609faadc3ec60077127a7ef7e8ac8b</id>
<content type='text'>
It printed 374 lines: every output format, the RFC 4180 quoting rule, the
template scope hazard, the publish manifest semantics. All of that is real
documentation and all of it is already in colitur(1), installed beside the
binary. A help text nobody reads at the terminal is not more helpful than a
short one, it is less -- the reader stops looking.

Now 42 lines: the commands, the flags most runs need, the year domain, the
exit status, and where the rest lives. Everything removed is in the man
pages, which is checked rather than assumed -- each dropped section has a
counterpart section there.

One thing moved rather than went. cli.t pinned `rubrics`' documented field
list against what `rubrics` actually prints, because that field count drifted
once already and stayed wrong for a whole review round. Deleting the prose
would have quietly retired the check, so it now reads the worked example out
of man/colitur.1 instead, and test/dune's cram stanza gains the man page as a
dep -- a sandbox holds only what that stanza names. Mutation-tested: changing
the documented example reddens the suite.

The tagline also stopped saying "Roman rite, 1962" -- the OF has shipped since
v1.1.0.
</content>
</entry>
<entry>
<title>test(of): pin the six corrupt Year II Gospels in Ordinary Time</title>
<updated>2026-08-28T14:15:13Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-28T14:15:13Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=4fb9eac2fdb9bc22af2b63c1d5df6da7780b58cf'/>
<id>urn:sha1:4fb9eac2fdb9bc22af2b63c1d5df6da7780b58cf</id>
<content type='text'>
Built the litcal readings comparison the OF provenance notes had left as
future work, and it found a defect class the existing layers structurally
could not see: the litcal layer compares season, grade and identity, and
stops there, so every reading colitur serves has been validated by nothing
except the lineage it arrived on.

Ten references are corrupt. Nine end at verse 22 where the OLM ends them at
20; the tenth reads "Matthew 17:9a,10-135", a verse Matthew 17 does not have.
Every one lives in a Year II entry or in of-advent-2-saturday, which has no
year cycle -- not one Year I entry is affected, which is what makes this a
transcription fault rather than ten independent slips.

This commit adds only the detection, and only for the six the invariant can
reach. In Ordinary Time the OF weekday Gospel does not depend on the year of
the cycle: OLM n. 69 point 4 alternates the FIRST reading and leaves the
Gospel a single one-year series. So of-ordinary-time-&lt;n&gt;-&lt;day&gt;-i and its -ii
twin must carry the same Gospel string, and six pairs do not.

Scoped to Ordinary Time deliberately. The unscoped sweep reports 17 further
disagreeing pairs in of-advent-3/4-* and of-christmas-*, all of them correct:
those weekdays are keyed to the calendar DATE (OLM n. 69 point 3), so their
-i/-ii entries describe two different dates rather than two years of one
cycle. An unscoped test would report seventeen false positives and would,
rightly, be switched off by whoever read it next.

Pinned rather than green, because the fix is not ours to make here:
data/of/lectionary.sexp's own header forbids hand-editing a generated
artifact, and lectio's internal/caldata/of-lectionary.ini carries all ten
verbatim. The exact six are listed, so the test fails if a seventh appears
and equally if one is fixed without updating the list -- both are changes a
reader must see.

Mutation-tested in both directions: introducing a seventh violation reddens
it, and correcting Mark 1:14-22 reddens it too.

Evidence for the corrections, in docs/research/of/olm-1981-ocr.txt, the Latin
OLM itself rather than a witness: "Mc 1, 14-20", "Mc 4, 1-20", "Mc 5, 1-20",
"Mt 7, 15-20", "Mt 17, 14-20", "Mt 18, 15-20", "1 Sam 1, 9-20",
"1 Sam 3, 1-10. 19-20", "Mt 17, 10-13". litcal independently confirms three of
the six Gospels and all four references the invariant cannot reach. James
5:13-22 is unlocatable in the OCR but impossible on its face: James ends at
5:20.
</content>
</entry>
<entry>
<title>Merge branch 'cli-pretty'</title>
<updated>2026-08-28T08:03:37Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-28T08:03:37Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=d0807440309e2357d51cd56c72a443072b0ba57f'/>
<id>urn:sha1:d0807440309e2357d51cd56c72a443072b0ba57f</id>
<content type='text'>
--pretty, and the --month/--date/--today flags that make it usable: a box
spans seven lines, so the flag that improved reading had removed grepping.
</content>
</entry>
<entry>
<title>chore: 1.2.0</title>
<updated>2026-08-28T08:03:32Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-28T08:03:32Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=8ba98d24499bedbc2491bd56268ea4f69aaddb2f'/>
<id>urn:sha1:8ba98d24499bedbc2491bd56268ea4f69aaddb2f</id>
<content type='text'>
Two presentation flags and no change to what is computed. Nothing was removed
and no default output moved, so a minor bump.

The CHANGELOG entry for 1.1.0 is backfilled here: that release was tagged
without one, which would have left this file jumping 1.0.0 -&gt; 1.2.0. Its
content is taken from the v1.1.0 tag message rather than reconstructed.

README's status section claimed the OF module lived on an unreleased branch
and counted 887 tests, and its build block advertised the fast suite at ~8s
and the exhaustive sweep at ~80s. Every one of those was true when written and
none is now: 909 fast (~40s), 916 under the sweep (~8min). Stale suite timings
are a defect this project has corrected once before, in 0.10.0.
</content>
</entry>
<entry>
<title>feat(cli): --month, --date and --today narrow a report</title>
<updated>2026-08-28T08:03:27Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-28T08:03:27Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=b39c8187ef1b87eea084e3c3d2226be5cf320dca'/>
<id>urn:sha1:b39c8187ef1b87eea084e3c3d2226be5cf320dca</id>
<content type='text'>
--pretty made a report readable and, in the same stroke, ungreppable: a box
spans seven lines, so `grep 2026-03-` returns fragments of March rather than
March. The nearest working equivalent is a paragraph-mode awk incantation that
depends on the boxes happening to be blank-line separated -- knowledge no
reader should need to select a month.

The three flags are ALTERNATIVES, not a stack. Naming two exits 2 rather than
letting one quietly win, the same discipline the positional year and --year
already follow, and the same reason this program refuses a flag it cannot
honour instead of accepting and ignoring it.

--date and --today CARRY a year, so the year becomes optional on those two and
required only after the window has had its say: `colitur day --today` is a
complete command while `colitur day` still is not. A year named alongside them
must agree. The disagreement message names the flag rather than printing two
bare numbers, because with --today the second year appears nowhere on the
command line for the reader to trace.

temporal refuses --year yet accepts --date/--today including as its year
source. That is not a back door to the refused spelling: --year is a second
spelling of the positional year, which temporal deliberately does not offer,
whereas --date selects a DAY and merely happens to determine which year
contains it.

The window is a predicate over an ISO date STRING rather than over a Date.t,
because the two report shapes reach it differently -- resolved days carry a
Date.t, temporal_report carries a flat Record whose date is already text --
and one shared test is one implementation rather than two that can drift.

Accepted by day, readings, rubrics and temporal; refused by easter, emit,
table, render, publish, check, convert, lang, config and new-overlay.

--pretty had shipped undocumented in both --help and colitur(1). Both now
carry it, alongside the new narrowing section; the man page's awk example is
shown precisely so the flag that replaces it is justified.

Default output is byte-identical to 1.1.0 across seven years, five commands
and both rites, and across all five emit formats and the shipped templates.
</content>
</entry>
<entry>
<title>feat(cli): --pretty draws each day as an ASCII box</title>
<updated>2026-08-27T13:45:49Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukasz@arcofasiagroup.com</email>
</author>
<published>2026-08-27T13:45:49Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=f1d562a3a4d53a707385334ab553b8a6cad36b1b'/>
<id>urn:sha1:f1d562a3a4d53a707385334ab553b8a6cad36b1b</id>
<content type='text'>
Aligned columns made the fields legible but the days ran together -- with 365
of them the eye had nothing to catch on. Each day now gets its own box: a
heading carrying the date and the liturgical colour, then the celebration, its
rank and season, and any commemorations, each on its own line.

The box art is pure ASCII, only + - and |, never Unicode box-drawing. That is
the point rather than a limitation: this format exists to be pasted or piped
into a document, a mail or a plain-text ordo, and U+2500 and its relatives
survive that only when every stage agrees about encoding and font. +---+ has
never failed to render anywhere.

readings gets a labelled block, so a citation says what it is instead of being
the second of three bar-separated fields; the OF second reading simply omits
its row on the days without one. rubrics becomes a label/value list. temporal
is the day box minus the sanctoral it does not have.

A blank line separates consecutive boxes -- without it the bottom rule of one
day and the top rule of the next sit adjacent and read as a single doubled
line, which is the same "not distinct enough" this change set out to fix.

Alignment counts UTF-8 code points, not bytes, so "Pen~afort" and "Fremiot"
still line the right edge up at 76 columns; a byte-counting pad shears the box
by one per multi-byte character. Over-long values are truncated with a ~
rather than allowed to overflow, since a box whose right edge does not line up
is worse than a clipped name that the default output still carries in full.

Verified: no ANSI escape reaches a pipe on any of the four commands, and the
default output is byte-identical to installed 1.1.0 across all five.
</content>
</entry>
<entry>
<title>feat(cli): --pretty, for reading in a terminal</title>
<updated>2026-08-27T12:12:43Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukasz@arcofasiagroup.com</email>
</author>
<published>2026-08-27T12:12:43Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=34a36fcb0956db7f06c4b8860414283c03996293'/>
<id>urn:sha1:34a36fcb0956db7f06c4b8860414283c03996293</id>
<content type='text'>
The row commands print for awk: single-space fields, slugs, a variable tail.
That is right for the default and wrong for a person, who mostly wants to know
what today is.

--pretty gives the same four commands -- day, readings, rubrics, temporal --
aligned columns, the day's liturgical colour as a swatch, and commemorations
on their own indented line rather than lengthening the row. The colour was
already computed and simply thrown away on a terminal.

Colour is written only when stdout is a terminal, so piping or redirecting
yields plain aligned text: the alignment survives, the escapes do not, and the
swatch degrades to the colour's initial so the information is not lost with
them. NO_COLOR is honoured on PRESENCE whatever its value, which is the
convention's own rule -- treating it as a boolean is the usual way to get it
wrong.

Every other command refuses the flag rather than accepting it and doing
nothing: emit, table, render and publish already choose their shape through
--format and --template, and easter prints six key/value lines, not a grid.
An intermediate version accepted it everywhere and silently ignored it on
five commands, which is the failure mode this program refuses everywhere else.

Two things the layout had to learn. Column widths are a minimum, not a
maximum: the Latin season names run past them ("Tempus per annum ante
Septuagesimam" is 35 against 34), so pad always leaves a separator or the next
field fuses onto it -- that is how "Septuagesimam 1S. Hilarii" happened. And
the commemoration indent is measured from the row actually printed rather than
computed from the column constants, or it sits under the wrong column on
exactly the rows that have something to indent.

Presentation only: bin/pretty.ml decides nothing about what a day is, and
nothing reads it. Default output is byte-identical to v1.1.0 -- verified
across day, readings, rubrics, temporal and easter for 2026, 1583 and 9999.
</content>
</entry>
</feed>
