<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/lib/kernel/rite.mli, branch v1.1.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.1.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v1.1.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-26T21:40:17Z</updated>
<entry>
<title>fix(of): anticipate St Joseph onto 18 March per Normae n. 56(f)</title>
<updated>2026-08-26T21:40:17Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-26T21:40:17Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=2f6d25aff88b4c76c61e36889f1c017b3cc8faee'/>
<id>urn:sha1:2f6d25aff88b4c76c61e36889f1c017b3cc8faee</id>
<content type='text'>
W1: when 19 March (St Joseph) falls on Palm Sunday, colitur sent him
forward to Easter+9 instead of anticipating the solemnity backward to
18 March, the one rule in the whole Normae transfer machinery that
names an earlier date. Live in 16 of 1583-2100 (1595, 1606, 1617,
1690, 1758, 1769, 1780, 1815, 1826, 1837, 1967, 1978, 1989, 2062,
2073, 2084).

Blocked on a kernel contract: Rite.t.transfer_target required its
result be strictly later than the impeded date, an obligation argued
purely from the EF's RG 96. Traced against Calendar's actual placement
pass rather than assumed unsafe: the round loop re-resolves the whole
year fresh every round, and its two safety nets (~start/~stop; the
round-count guard) both test the target's own value with no comparison
against origin, so a bounded backward jump converges the same way a
bounded forward one does. The one requirement that stays load-bearing
is target &lt;&gt; origin: Precedence.resolve never deduplicates by slug, so
a candidate returning its own argument unchanged would collide with
itself in the same round's contest. Relaxed the obligation accordingly
(rite.mli) and added the fourth transfer_target branch in
Precedence_of, ahead of the existing three (Precedence_of.transfer_target,
Rule 0). calendar.ml needed no logic change, only two comments that
asserted "every genuine transfer moves forward" as a blanket fact.

Unpinned the two tests that asserted the old wrong (forward) behaviour
and replaced them with assertions of the correct one, plus a new
direct unit test of the backward branch across two independent years.

EF output is untouched: data/ef/ and lib/rites/rite_ef/ carry no diff,
and colitur day/readings for 2026, 1583 and 9999 are byte-identical
against a build of the prior commit. OF's own 2005-2050 window carries
none of the 16 affected years and shows zero unexpected diffs; the
full 1583-9999 domain still reaches a fixed point under the exhaustive
sweep.
</content>
</entry>
<entry>
<title>fix(citation): make the well-formed reading-part set rite-supplied</title>
<updated>2026-08-26T12:28:50Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-26T12:28:50Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=e5cbc662227de4f3ab0089fe73f639f4f84601a4'/>
<id>urn:sha1:e5cbc662227de4f3ab0089fe73f639f4f84601a4</id>
<content type='text'>
I7 (final-review.md, 2026-08-25-colitur-of-phases-3-5): OF Sundays and
solemnities shipped without the Second reading, and the lectionary
data header called the First reading an "Epistle" -- EF vocabulary.
The sole blocker was Validate's own kernel-hardcoded assertion that a
well-formed day's sorted citation parts are exactly [First; Gospel];
Citation.part already carried Second.

Rite.t gains citation_shapes : Citation.part list list, the fourth
EF-shaped kernel misfit (after Preface.t, Mass_formulary.source,
transfer_target's strictly-later contract) and the first fixed rather
than only documented. EF supplies its one shape unchanged; OF supplies
two, [First; Gospel] on a feria/feast/memorial and [First; Second;
Gospel] on a Sunday or solemnity (OLM 1981 Praenotanda n. 66.1 vs
n. 69.1, n. 84(b)/(c), page-image verified against olm-1981.pdf).
Validate's "citations" check now matches against the rite's own
declared shapes rather than a single literal pattern, preserving all
three invariants it always enforced: zero or one complete shape, never
partial; no part outside what the rite declares; no part repeated.

bootstrap_lectionary_of.ml's cite now extracts a Second reading from
Sunday-cycle ini sections only, correctly excluding the one stray
`second` field lectio's snapshot carries on a weekday-cycle section (a
content-verified scraping artifact). The hand-authored Christmas Day
entry gains its own Second reading from the same OLM passage already
cited for its First/Gospel. Regenerated data/of/lectionary.sexp: 771
entries unchanged, citation fields 1542 -&gt; 1725 (+183, all Second
readings), SHA-256 re-pinned, header wording fixed and a new coverage
bullet added. Responsorial Psalm is deliberately still not emitted --
OLM 1981 Praenotanda n. 71 itself lists it apart from the readings
proper as a chant with its own refrain, and the finding driving this
change names only the missing Second reading.

EF output verified byte-identical to the branch start (empty
lib/rites/rite_ef + data/ef diff since v1.0.0, plus a direct binary
comparison of `day`/`readings` for 2026, 1583 and 9999 against a
worktree build of the pre-change commit).

Tests: three new fixtures in test_validate.ml prove the generalisation
holds both directions (a multi-shape rite accepts either of its
declared shapes; a rite that never declared a shape still rejects it).
test_citation_coverage_of.ml's pinned residual grows 41 -&gt; 49, all new
entries the same already-understood chapter-crossing shape.
</content>
</entry>
<entry>
<title>feat(ef): the Mass preface, RG 482-499</title>
<updated>2026-08-22T21:24:12Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T21:24:12Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=0806fe65e388a9502035bc9d4f551528ac74b26d'/>
<id>urn:sha1:0806fe65e388a9502035bc9d4f551528ac74b26d</id>
<content type='text'>
Item 2 of Phase 3 (celebrant-rubrics-phase1), the bulk of this phase
and the last EF Mass rubric this project scoped: which preface is
said, deferring to seasonal/proper-title rules for the fourteen named
prefaces, then RG 498's Common residual.

RG 482 gives the resolution chain: the Mass's own proper preface,
failing that the seasonal one, failing that Common. Read literally,
RG 484-497 look like fourteen separate rules, but each numbered
rubric's own propria/de-Tempore pair produces the SAME preface
identity either way, so the whole chain collapses into one priority-
ordered decision: title/mystery triggers (Holy Cross, Sacred Heart,
Christ the King, Trinity, St Joseph, BVM, the Nativity octave, the
Apostles, Epiphany), each independent of season, then six seasonal
windows (Nativity, Epiphany, Lent, Holy Cross/Passiontide, Easter,
Ascension, Holy Spirit, Trinity-for-ordinary-Sundays), then Common.

The "one genuinely unproven piece" the design spec worried about --
per-feast proper prefaces extracted from the Missal's propers at scale
-- turned out not to be a large-scale extraction problem at all: every
one of the fourteen propers is a closed, small, subject/slug-keyed
trigger (mirroring Precedence_ef.band's own RG 91 table), not
thousands of individual saints' pages. The one genuine open question
(RG 488, the Chrism Mass) is N/A: this engine resolves one Mass per
civil day and has no separate Chrism-Mass dimension.

Preface is a new kernel type (lib/kernel/preface.ml[i]), not an
EF-specific one, the same placement as Colour/Subject/Mass_formulary:
Liturgical_day.t is parameterised only over season/rank, so any field
it carries generically must live in the kernel even though only EF
constructs a value of it today. Wired exactly as creed/gloria were
(Rite.t.preface, Calendar.ml, Rite_ef.context), but Preface.t option,
not a bare bool: unlike creed/gloria, a preface is said only at a
Mass, and Good Friday (1955-restored Holy Week) resolves an observed
celebration but has no Mass at all -- None is the honest answer there,
and also the neutral value an unimplemented rite returns.

Two priority-order findings only the oracle settled, not derivable
from the Latin text in isolation, both cross-checked against 358
individually classified entries in the FIUV Ordo's own praef column
(test/fixtures/fiuv-ordo-2025-2026.sexp, already captured, wired up
here as a new comparison axis): RG 484(b)'s own "except Masses with a
proper of the divine mysteries or Persons" is narrower than every
other window's implicit exception (an Apostle inside the Nativity
octave is overridden to Nativity; outside it, keeps his own preface
even inside another window); and RG 495's "et votivis" half is live
for the one office this engine models without a votive-Mass dimension
(the Saturday Office of the BVM), which also proved a vigil is not a
"festum" for this purpose (the Assumption's own vigil takes Common,
not BVM, correcting an initial reuse of Precedence_ef.marian_slugs
that had no reason to make that distinction for its own, different
rubric). A third, RG16(a)-shaped fix landed the same way: RG 494(b)'s
own Trinity grant must read the day's TEMPORAL season, not the
celebration that actually won it, or a Class1 feast with no preference
of its own (All Saints) wrongly falls to Common on a Sunday it merely
commemorates.

colitur rubrics gains a sixth TAB-separated column. Domain-wide
1583-9999 exhaustive sweep confirms every Christmastide day resolves
Nativity/Epiphany/Bvm, every Paschaltide day one of its own three
windows or a season-independent title, every Lent day Lent or a
title, and Passiontide legitimately produces Easter exactly once a
year (the Vigil Mass) -- 8416 of the domain's 8417 years, the one
short year being the domain's own upper boundary (the liturgical year
opening in 9999 cannot construct dates in year 10000, a pre-existing
edge this sweep re-confirms rather than a new one).

day/readings verified byte-identical to the branch's own state before
this phase (commit 9c96e0a) across a 455-year sample spanning the
whole domain -- not literally to the v0.10.1 tag, which 22 earlier
commits on this same branch (Phase 1/2, the bissextile shift, the
Rogation colour fix) had already moved past before this phase began.
</content>
</entry>
<entry>
<title>feat(ef): the Gloria in excelsis, RG 431-432, deferring to Breviary 237-238</title>
<updated>2026-08-22T15:56:42Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T15:56:42Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=f4cc032d7e812d716ff6b5df8192f79a2560e8f0'/>
<id>urn:sha1:f4cc032d7e812d716ff6b5df8192f79a2560e8f0</id>
<content type='text'>
Phase 2 of celebrant-rubrics-phase1: colitur rubrics gains a fifth
column, whether the Gloria is said. Follows the Creed's own seam
exactly -- Rite.t.gloria, Liturgical_day.t.gloria, wired through
calendar.ml the same way.

RG 431(a)/432(a) defer the Gloria to the Breviary's own Te Deum rule
(nn. 237-238), so te_deum is implemented as its own named predicate,
cited clause by clause, not collapsed into a colour heuristic. 431(c)
(Holy Thursday, the Easter Vigil Mass) and 432(b)/(d) (violet; a
Requiem) are independent overrides checked ahead of the Te Deum-derived
answer. Every clause this engine has no dimension to model
(votive Mass classes, the wider n.302 "Missa festiva" categories) is
stated as N/A with its own reasoning, not silently dropped.

Validated against the FIUV universal Ordo (Gloria and Te Deum) and all
three LMS editions (Gloria). A first pass over-trusted a clean-looking
15-for-15 FIUV contradiction of 237(b)'s own Septuagesima exception and
replaced it with a blanket "every Sunday" rule; the evidence was itself
corrupted -- the FIUV extractor recognised only one of the source's two
Te Deum negations ("non dicitur", not "sine"), so every "sine Te Deum"
Sunday read wrongly true. Fixed in tools/extract_fiuv_ordo.ml, fixture
re-extracted, and the literal 237(b) reading restored once the
corrected data confirmed it. A second bug surfaced alongside it (Palm/
Passion Sunday wrongly reading true via Temporal_ef.named's own table
membership, then Christ the King wrongly reading false from an
over-broad fix) is closed with an explicit two-slug exclusion.

Domain-wide 1583-9999: every violet or Rose day is gloria=false except
the Easter Vigil (RG 431(c) lex specialis), every Requiem is
gloria=false, both measured exhaustively, zero exceptions. Mutation-
proved: disabling 431(c) reddens 8 tests including all four oracle
comparisons; disabling 238(c)'s feria-I-classis exclusion reddens
exactly the dedicated Ash Wednesday unit test, a genuine blind spot in
both oracle layers, reported rather than hidden.

Two open, cited findings, neither fixed here (out of this task's
"follow creed's exact seam" scope): a privileged Lenten/Passiontide
feria carrying one commemoration reads Gloria=true in the LMS Ordo but
Te-Deum=true/Gloria=false in FIUV -- the two oracles disagree with each
other, not merely with colitur (data/ef/expected-divergences-lms.sexp
L5, expected-divergences-fiuv.sexp F3); and a pre-existing, uncited
Colour.Violet bug on Rogation Monday/Tuesday in Temporal_ef.temporal,
surfaced by this comparison but root-caused as a separate defect (L6).

day/readings verified byte-identical against a build from the branch
tip before this task (v0.10.1's own tag predates an already-landed
bissextile fix that legitimately changed both, so it is not the right
baseline).

671 tests green (dune test); 678 with the exhaustive sweep
(COLITUR_EXHAUSTIVE_SWEEP=1 dune test --force, ~104s).
</content>
</entry>
<entry>
<title>feat(ef): implement the calendarium's bissextile February shift</title>
<updated>2026-08-22T14:40:24Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T14:40:07Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=60e87914718dd2c8e69bb89d8cc48d6bef9bfc74'/>
<id>urn:sha1:60e87914718dd2c8e69bb89d8cc48d6bef9bfc74</id>
<content type='text'>
The Missale Romanum's calendarium footnote for February (LT.txt:5011-5014,
scan-corroborated scan2.txt:3050-3058): in a leap year the sixth kalends of
March (24 February) is doubled rather than a 29th day appended, so St
Matthias moves 24-&gt;25 February and St Gabriel of Our Lady of Sorrows
27-&gt;28, with 24 February itself carrying no fixed office that year.
data/ef/expected-divergences-lms.sexp entry L3 tracked this as an open gap.

Implemented as the rubric's own general mechanism (every fixed entry from
24 through 28 February shifts one civil day later in a leap year), not as
"move these two named saints": the two readings are indistinguishable on
shipped data (nothing else is fixed in that window) and diverge only for a
future --overlay entry in the same range, which the mechanism reading
covers correctly and a two-saints special case would not. This project has
already been bitten once (RG 16(a)) by a rule implemented against shipped
data's coincidental shape rather than the rubric itself.

Kernel stays rite-agnostic: Rite.t gains a fixed_key field (Date.t -&gt; (int
* int) option), the same seam easter already establishes, read only by
Layer.on_date's FIXED half -- the movable half (Easter_offset/Nth_weekday)
is untouched. Default is the identity mapping, an optional argument on
on_date, so every existing caller and every rite that supplies nothing is
byte-identical to before this field existed. Date.is_leap is exposed in
date.mli (already existed in date.ml) so the rite reads the kernel's own
single-sourced leap-year definition. The EF implementation lives in
Rite_ef.Temporal_ef.bissextile_fixed_key, fully cited, wired into
Rite_ef.context.

Blast radius, measured over the full 1583-9999 domain (Calendar.year run
twice per civil year, real fixed_key vs identity, every day diffed): all
2,041 leap years in the domain show a visible change for each saint;
6,983 individual liturgical days change total, zero unclassified, across
four shapes (Matthias vacates 24 Feb in 1,803 years / occupies 25 Feb in
1,811; Gabriel vacates 27 Feb in 1,699 / occupies 28 Feb in 1,670).
L3's own prior estimate (1,650 years, observed-outright only) is confirmed
close on the same definition (1,677 measured); the broader observed-or-
commemorated count is higher, not lower, showing the narrow estimate
undercounted visible impact rather than overcounting it.

The lectio differential (2005-2050 fixture) gains a new cited entry, C40
in data/ef/expected-divergences.sexp: lectio implements no such shift, so
every leap year in its window now diverges on the two shifted days (21
rows, not the naive 44 -- the comparator never compares commemorations, so
a side where the shifted saint has zero comparator-visible footprint on
both engines produces no row). The LMS Ordo's 2023-2024 fixture -- the
window L3 was originally found in -- now matches on the Creed comparison;
its formulary-override bucket count is corrected 182-&gt;181 (24 February
leaves the counted Proper population, becoming Own_slug-sourced). The
missalemeum oracle fixtures (2026-2027, 2038, 2035) cover no leap year and
are unaffected.

L3 is closed: converted from an active allow-list record to a prose
closure paragraph (L1's own precedent), citation preserved verbatim, fix
and measured blast radius recorded. The id-list assertion narrows to [L4]
alone, and the now-dead "2024-02-24" -&gt; "L3" date mapping is removed.

Six golden values pinned across four new test cases: Matthias in a leap
year (both the vacated and occupied sides) and a common-year control;
Gabriel likewise, deliberately choosing a leap year where he is admitted
only as an ordinary commemoration rather than winning outright, a
different shape from Matthias's.

Mutation-tested: forcing fixed_key back to identity reddens exactly five
test cases -- the differential's Layer C count-pin (C40 drops to 0 actual
vs 21 expected), the LMS Ordo's Creed and formulary-bucket checks, and
both new golden pins -- confirming the tests actually exercise the fix.
Reverted; dune test, the exhaustive sweep, and make check are all green.
</content>
</entry>
<entry>
<title>feat(ef): the Creed, RG 475-476</title>
<updated>2026-08-22T10:02:01Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T10:01:48Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=d4682c13161b62bc83eaae37790493f670d39c01'/>
<id>urn:sha1:d4682c13161b62bc83eaae37790493f670d39c01</id>
<content type='text'>
Whether the Creed is said at Mass. New Rubrics_ef.creed, reached through
a new Rite.t.creed field and a new Liturgical_day.t.creed bool (false,
not an option, for a rite that has not implemented the rule); colitur
rubrics gains a fourth TAB-separated column.

475(a) reads the TEMPORAL cycle's own weekday, not the observed day: a
Sunday impeded by a Feast of the Lord (RG 16a) still says the Creed.
475(d)'s three octaves (Nativity, Easter, Pentecost) are pure date/
Easter-offset windows, checked first, since a saint's feast winning the
day inside one of them still says the Creed ("etiam in festis
occurrentibus") -- St Stephen, 26 December, is the live witness.

RG 23 classifies Ash Wednesday and every feria of Holy Week (including
the Sacred Triduum) as feriae, not festa, however high their rank, so
475(b)/(c)'s "in festis" never reaches them; this single check subsumes
476(a)'s own naming of the Chrism/Lord's-Supper Mass and the Easter
Vigil. RG 28-34 vigils are a third liturgical-day category, also
excluded from "in festis" regardless of rank -- reuses the already-
exported Precedence_ef.is_vigil rather than a new list.

475(e)'s Apostle/Evangelist natalicia list (creed_apostle_slugs) was
derived by grepping data/ef/sanctoral.sexp directly and checking each
candidate's own date against whether it is that saint's dies natalis --
not copied from any list supplied with the task. The Conversion of St
Paul and the 30 June Commemoration of St Paul are excluded (neither is
a natalicium); the Chair of St Peter and St Barnabas are included only
because the clause names them explicitly, which is exactly why it has
to: neither is a natalicium either.

475(c)'s BVM half reuses Precedence_ef.marian_slugs (newly exported)
rather than the subject field alone: checked against the shipped data,
almost every Marian sanctoral entry ships subject=Saint, not Bvm.

man/colitur.1's rubrics section is updated to match the new column;
test/cli.t repinned via dune promote for the same reason. Verified
day/readings output byte-identical to v0.10.1 across the whole
1583-9999 domain (both binaries' concatenated day+readings output,
6,148,492 lines each, zero diff). Domain-wide: 882,996 days say the
Creed, 2,191,250 do not; every one of the domain's 439,178 Sundays says
it, zero exceptions.
</content>
</entry>
<entry>
<title>feat(kernel,ef): the lectionary reports which Mass it said</title>
<updated>2026-08-21T20:39:12Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-21T20:39:12Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=384b0789c0f4d9beb936080a5592bb4aa6134295'/>
<id>urn:sha1:384b0789c0f4d9beb936080a5592bb4aa6134295</id>
<content type='text'>
Rite.readings now returns (Mass_formulary.t option * Citation.t list)
instead of a bare citation list, and Liturgical_day.t carries the result
as a new formulary field. Validate holds a rite that resolves a formulary
at all to resolving one on every day, the same discipline it already
applies to citations; the EF lectionary chain resolves Some on every day
of every year 1583-9999, confirmed by a direct sweep over 2005-2050 as
well as through Validate itself.

Plan Tasks 2 and 3 are merged into this one commit on the coordinator's
own instruction: Rite.readings' signature and the field that consumes it
are one atomic edit, and the intermediate state does not compile on its
own.

Each of the four lectionary steps now builds its own Mass_formulary.t at
the point it decides, not by re-deriving it afterwards from the citations
it returns: step 1 tags Proper with the observed slug, step 2 tags
Own_slug with the day's own temporal slug, step 3 tags Preceding_sunday
with the resumed Sunday's temporal slug, and step 4 tags Common with the
Common's own id -- Commons.find now returns that id alongside its
citations rather than discarding it, since it is only ever in scope at
the point the assignment is looked up.

The RG 309(a) Saturday votive Mass of Our Lady, which answers between
steps 4 and 2 rather than as one of the four numbered steps, is tagged
Own_slug too: Mass_formulary.source has no dedicated constructor for it,
and its own guard only ever fires when the observed celebration already
is the day's own (reused ferial) temporal slug, which is exactly what
Own_slug documents. Recorded as a judgement call in the task report, not
a specified answer.

test/cli.t's `emit --format sexp` line count is repinned (8472 to 8881):
that command serializes Liturgical_day.t whole, so the new field grows
its output. `colitur day` itself is untouched -- verified byte-identical
against the pre-change binary across 1583, 1900, 2026, 2038 and 9999.
</content>
</entry>
<entry>
<title>feat(kernel): movable Date_spec variants, and Rogation Wednesday</title>
<updated>2026-08-17T15:22:43Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-17T15:22:43Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=2b9f8133a22ce6dc309644a98bbe61507f574b38'/>
<id>urn:sha1:2b9f8133a22ce6dc309644a98bbe61507f574b38</id>
<content type='text'>
Date_spec carried one variant, Fixed(month, day), and its own header said
Sunday- and Easter-relative forms would arrive with the OF sanctoral. They
arrive early because two things needed them at once: a user-supplied
overlay carrying a local movable feast had no way to express "the first
Sunday of October", and Rogation Wednesday's commemoration has been
recorded as architecturally blocked since 2026-08-13.

That blockage turns out to have been a premise, not a fact. The register
concluded the Rogation "is not Commemoration_only sanctoral data by
nature... it needs a genuinely THIRD kind of thing this architecture has
no name for" -- but the reasoning rested on there being "no civil (month,
day) pair to anchor a Fixed entry to". That is a statement about
Date_spec's expressiveness. With Easter_offset the entity is ordinary
sanctoral data, the identical shape Add major-litanies already ships,
differing only in how the date is written. No third channel was needed.
The register is corrected rather than left contradicting the code.

Two variants: Easter_offset of int, and Nth_weekday of {month; nth;
weekday} with negative nth counting from the end. Fixed's sexp
representation is untouched, so all 327 sanctoral entries and the whole
overlay parse unchanged. Both are re-validated in t_of_sexp through their
smart constructors, extending the idiom Fixed already used -- the failure
that guards against is invisible, a spec deserialising into something
that silently never resolves and a celebration vanishing with no
diagnostic.

Easter is supplied by the rite, not computed in the kernel. Computus
ships Gregorian and Julian both, and picking one here would hard-code a
Roman assumption into rite-agnostic code and be silently wrong for a
Julian-reckoning rite. Rite.t gains an easter field; Rite_ef supplies the
Gregorian one.

Layer keeps a split index. Fixed entries stay in the year-independent
(month, day) table, which preserves the fast path and the "30 November
counted twice in a 371-day span" behaviour validate.mli documents for St
Andrew. Movable entries have no year-independent key by construction --
the same spec lands on a different (month, day) each year -- so they
resolve per civil year into a rata-die table. index_by_date is removed
rather than kept as an alias: two ways to index a layer, one of which
silently ignores movable entries, is the trap this change exists to
avoid.

Two domain-edge defects, both found by the suite rather than reasoning. A
liturgical year is Advent-anchored, so resolving civil year y names y +/-
1, and at the edges those are 1582 and 10000, which Computus correctly
refuses by raising. The ceiling surfaced through the domain-ceiling test,
the floor through `colitur day 1583` failing outright. Fixed once, in
Layer.index, the single point that calls the rite's easter -- a clamp
repeated per caller would have been two places to get wrong a third time.

Rogation Wednesday: RG 87 assigns the Litaniae minores to the Monday,
Tuesday AND Wednesday before Ascension (scan1:691); colitur built the
first two from the start and never the third. RG 88 keeps it out of the
Office, so the Ascension Vigil remains observed. RG 89 routes it through
the Major Litanies' rules, but RG 109's closed list names only maiores,
so by RG 107 it is an ORDINARY commemoration -- confirmed in the output,
not assumed. Name from the Missal's own "feria IV" (scan1:20495-20497),
violet to match the Monday and Tuesday offices.

Blast radius, full 1583-9999 sweep against the pre-change binary: 2257
days, every one the same shape, zero unclassified, line counts equal both
sides. The complement is the informative half -- in the other 6160 years
the Rogation does not appear at all, because RG 111 admits one
commemoration on a II-class day and an impeded feast takes it under RG
113, a Commemoration_only candidate having no row in RG 91's table. Both
shapes are pinned.

Allow-lists unmoved: layer 3 compares no commemorations and is blind by
construction, and layer 4's 2026-2027 window has a competing feast on
both Wednesdays, so the Rogation is capped out in exactly the years the
oracle can see. C8 is unchanged, asserted by its own count pin.

Not built: Sunday-relative specs, which nothing needs yet, and the
--overlay plumbing that would let a user actually supply a local movable
feast. Nth_weekday therefore ships with synthetic and property coverage
only; inventing a shipped entry to exercise it would be fabricating
calendar data.

Register: section 6.10.
</content>
</entry>
<entry>
<title>kernel+ef: resolve readings, chain steps 1 and 2</title>
<updated>2026-08-14T22:16:35Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T22:16:35Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=124d7e2261c721c4a49f7203efc276088c7cb217'/>
<id>urn:sha1:124d7e2261c721c4a49f7203efc276088c7cb217</id>
<content type='text'>
Liturgical_day.citations has read "always empty until Plan 4" since Plan 3;
it is now filled. Rite.t gains a readings function, rite-supplied for the
same reason transfer_target is: what a day with no proper falls back to is a
rubric, not a universal. Calendar calls it and passes its own temporal
function as the callback the rite needs to reach another date.

Steps 1 and 2 only: the observed celebration's own proper, else the day's own
temporal slug. Nothing encodes "Lent has daily propers" -- the presence of an
entry is the discriminator.
</content>
</entry>
<entry>
<title>cli: colitur day &lt;year&gt; dumps resolved liturgical days</title>
<updated>2026-08-11T22:44:36Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T22:44:36Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=7f183c847f8b67c88ad6ea3bf2d635c5c0534651'/>
<id>urn:sha1:7f183c847f8b67c88ad6ea3bf2d635c5c0534651</id>
<content type='text'>
Assembles Rite_ef.context (lib/rites/rite_ef/rite_ef.ml[i]): temporal,
anchors and vocab from Temporal_ef; rules from Precedence_ef's band,
disposition and admit; season_runs = Vocab_ef.seasons; transfer_target
newly implemented here.

transfer_target (RG 96): the next following day that is not I or II
class, with the Annunciation's own exception (Monday after Low Sunday).
Terminates by a structural step bound on its internal search, independent
of Calendar's own round guard, which bounds rounds across a year, not one
call's walk; documented as an obligation on rite.mli's transfer_target
field, which did not previously state it.

Fixes the vigil-naming mismatch Task 7's review predicted: the sanctoral
bootstrap names its vigils with a vigil-of-X prefix (lectio's own
convention), while Precedence_ef's is_vigil only recognised the temporal
cycle's own X-vigil suffix. Both are now recognised, fixing RG 91 entries
21/26 and RG 33's vigil omission for the four affected celebrations.
Verified by unit test and by mutation-testing the fix (reverting it fails
exactly the new rows) and against real output across several years.

Suppresses data/ef/sanctoral.sexp's vigil-of-christmas via a new overlay,
data/ef/adjustments.sexp: it is the same celebration as the temporal
cycle's own ef-nativity-vigil, both dated 24 December.

colitur day &lt;year&gt;: one line per civil-year day, temporal and sanctoral
fully resolved through Layer, Overlay, Precedence_ef and Calendar -- the
first CLI path exercising the whole Plan 3 pipeline against real data.
Verified the All Souls transfer chain (Tasks 7-8-11) end to end against
real output for both a Sunday year (2025, lands on 3 Nov) and a
non-Sunday year (2026, observed directly on 2 Nov).
</content>
</entry>
</feed>
