<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/test/test_colitur.ml, 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-24T14:16:59Z</updated>
<entry>
<title>feat(ordo): wire the extraordinaryform.org preface column in as a third witness</title>
<updated>2026-08-24T14:16:59Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-24T14:16:59Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=0d061abc7cc5cdc51ded6ee69e00e187813f5e1b'/>
<id>urn:sha1:0d061abc7cc5cdc51ded6ee69e00e187813f5e1b</id>
<content type='text'>
Extends the preface comparison (RG 482-499) with a third, independent
publisher, extraordinaryform.org's three annual Ordo editions
(2024-2025, 2025-2026, 2026-2027), previously declined for two reasons
that are now resolved:

- "Advent" is not a preface: RG 494(b) grants the Trinity preface on
  every Advent SUNDAY, RG 498 the residual Common on every Advent
  FERIA; this source's own "Advent" label covers both indiscriminately
  (confirmed live on all 11 non-impeded Advent Sundays in the corpus).
  Classified by the day's own civil weekday, not a static table.
- The known Vigil-of-St-Lawrence gap is reconfirmed, with a nuance not
  present in the earlier audits: colitur's own RG33-third-trigger now
  omits the vigil in some years too, so the corpus's gap and colitur's
  answer coincide in 2025 (a full match, not a coincidence) while 2027
  still shows the classic identity-wrong-but-preface-invisible shape.

Re-derives the known menu-trap office filter (Requiem-skip, "and "-chain)
against the live JSON and finds a second, general pattern: "Saturday of
Our Lady" (RG78's BVM Saturday Office), whenever listed, is
unconditionally the office -- checked exhaustively across all 38
instances in the corpus, zero counter-examples. A third, generic
"absorption" rule was deliberately not built: it would resolve 2 of the
11 residual divergences but wrongly misfires on a structurally identical
but semantically different shape (an optional Rogation-day Mass option).

The JSON's own extraction carries a genuine classifier gap: parse_ordo.py's
hardcoded PREFACES set omits "Christ the King", misfiling it into comms;
recovered in the generator, not left blank.

11 of 1088 comparable rows diverge, resolving to 7 adjudicated root
causes (E1-E7): two Commemoration_only Marian titles reduced to
commemorations (Mt Carmel, Ransom), two genuine sanctoral data gaps
cross-confirmed absent by the FIUV/LMS witnesses (Miraculous Medal,
St John before the Latin Gate), two single-witnessed efdotorg outliers
against FIUV/LMS agreement (St Michael's Dedication, All Saints on a
Sunday), and one isolated source labelling slip.

Mutation-tested: corrupting the RG495 BVM-Saturday clause reddens 9
tests across this new layer and both existing Ordo witnesses.

Per-edition agreement: 358/363 (2024-2025), 358/363 (2025-2026),
361/362 (2026-2027).
</content>
</entry>
<entry>
<title>test(fiuv-ordo): add the FIUV universal Ordo as a second, independent witness</title>
<updated>2026-08-22T13:11:43Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T13:11:43Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=96aed1b6f04ef89e8f3d18af8b13e6fd30dbd4d2'/>
<id>urn:sha1:96aed1b6f04ef89e8f3d18af8b13e6fd30dbd4d2</id>
<content type='text'>
Wires in the FIUV (Foederatio Internationalis Una Voce) Ordo for
2025-2026 as validation layer seven -- the first UNIVERSAL (not
diocesan) source in this project, and the first compiled by someone
other than the LMS editions' own Peter Day-Milne (Joseph Shaw, FIUV
President).

tools/extract_fiuv_ordo.ml hand-parses pdftotext's -layout dump of the
Latin-language ordo (no Str/regex, frozen deps). Three real parsing
traps were found and fixed by tracing actual false results against the
raw source, not assumed in advance:

- "Gloria" is also the first word of "Gloria Patri" (the psalm
  doxology), which can appear INSIDE the very Mass clause being scanned
  (Good Friday: "...omittuntur ps. Iudica me et Gloria Patri), Gloria,
  sine Credo..."). Guarded by rejecting any "Gloria" hit whose next
  token is "Patri".
- Christmas Day's own rubric uses the PLURAL "Missae"/"Missae" ("tres
  Missae celebrantur..."), never the singular "Missa" every other real
  day anchors on -- silently produced gloria=None/credo=None on the one
  most doctrinally unambiguous day in the calendar until traced and
  fixed, guarded in turn against "Missae defunctorum" (an unrelated
  Requiem-prohibition notice appearing at the end of many day-blocks).
- The Vespers boundary (bounding the primary Mass option before a
  second "Vel Missa" alternative or before Vespers information) missed
  the ligature spelling "VESPERÆ", the dominant form in this source,
  letting a whole day's trailing prose leak into the captured [praef]
  field on the task brief's own worked example day (19 September).

A distinct second stop-marker bug: the malformed trailing entry this
source shares structurally with the LMS PDFs (a stray, mislabelled
duplicate of 1 January) was initially over-matched by a generic
"first token is 4 digits" heuristic, which false-positived on an
indulgence-decree date citation wrapped mid-sentence in October
("...20 augusti / 1885, 26 augusti 1886..."), truncating the extraction
to 308 of 400 real days. Fixed by anchoring on the tail entry's own
distinctive "1st Jan" opening instead.

Five opposite-prediction Creed probes are re-verified by the tool
itself against its own extracted rows (a failed probe is a hard exit,
not a printed claim) before the fixture is written.

test/test_fiuv_ordo.ml compares the Creed against colitur across all
399 comparable days (Holy Saturday excluded, no Mass that day) --
CLEAN, zero unexplained divergences, a genuine second confirmation of
{!Rite_ef.Rubrics_ef.creed} independent of the LMS lineage. [praef],
[te_deum] and [class_] (including the FIUV ordo's own "III cl." vs
"III cl. (Priv.)" Cum Sanctissima convention, stated on its title
page) are captured into the fixture but deliberately not compared --
colitur has no Gloria/preface predicate yet, and its default
configuration models no Cum Sanctissima overlay to compare the class
convention against.

All 634 tests green (dune test), 635 with the exhaustive sweep and
make check. No lib/ file touched.

Claude-Session: https://claude.ai/code/session_017ZBxCCRM2ojnBupp3SBxV9
</content>
</entry>
<entry>
<title>test(lms-ordo): extend the LMS witness layer from one year to three</title>
<updated>2026-08-22T12:51:07Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T12:51:07Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=72dd2426f020f83a392158ead7bd15b36088fd08'/>
<id>urn:sha1:72dd2426f020f83a392158ead7bd15b36088fd08</id>
<content type='text'>
Generalises tools/extract_lms_ordo.ml's start-of-body detection: the
hardcoded "End of November 2024" sentinel assumed every edition opens
with an "End of November" stub section. The 2023-2024 edition has none
(Advent Sunday 2023 fell on 3 December, so the compiler folded the two
tail days into the "December 2023" header directly) -- the generalised
detector anchors on the body's own "ORDO" title line instead, verified
unique in all three known editions and distinct from the Table of
Contents' lowercase "Ordo" entries.

Extracts test/fixtures/lms-ordo-2023-2024.sexp (397 rows) and
lms-ordo-2025-2026.sexp (399 rows), each with a provenance header
carrying its own SHA-256, source citation, and a per-edition
characterisation record: five opposite-prediction Creed probes,
independently re-verified against this run's own extracted rows (a
failed probe is now a hard die, not a printed claim). The 2025-2026
edition needed a different sharp II-class pairing than 2024-2025's
Joachim/Stephen one, because Joachim (16 August) is impeded by a Sunday
that year -- recorded in the fixture header, not silently swapped.

test/test_lms_ordo.ml is refactored into a parameterised make_suite,
instantiated once per edition; every count Task 6 hardcoded against the
single 2024-2025 window is now a per-edition parameter, several of which
turned out to differ once measured (BVM-Saturday population 12/14/13,
Ascension-week exclusion 1/3/2). Two mapping gaps surfaced only by the
new windows and fixed here (test-side, not colitur): Low Sunday reached
via Preceding_sunday for the first time (absent from 2024-2025's own
window), and the Ascension-week exclusion was wrongly keyed off week
number alone -- Rogation Monday also resumes week 6's Sunday but falls
BEFORE Ascension, not after, and the Ordo prints the ordinary Sunday
text there. Re-bounded by date, against Ascension and Pentecost.

Two genuine divergences surfaced in the 2023-2024 window and are
allow-listed (L3, L4) rather than fixed, per this task's no-lib-changes
scope:

- L3 (verdict ordo): colitur has no bissextile calendar rule. The 1962
  Missal's own calendarium moves St Matthias from 24 to 25 February in
  leap years (docs/research/LT.txt:5011); colitur keeps him on the 24th
  every year. Domain-wide upper bound measured with a throwaway sweep:
  1,650 of 2,041 leap years in 1583-9999 currently observe him there.

- L4 (verdict open): Christmas Eve falling on the 4th Sunday of Advent
  (2023-12-24, roughly 1 year in 7). colitur says the Creed is said,
  reading RG 475(a)'s Sunday clause; the Ordo says it is not. RG 30(a)'s
  own "locum tenet ... nulla fit commemoratio" for this exact vigil
  reads like RG 16(a)'s Feast-of-the-Lord-on-Sunday shape, which colitur
  already treats as Creed-preserving -- but RG 475(a) names "festo"
  specifically, and a vigil is its own liturgical-day category (RG 35),
  so the counter-reading is real too. Left open rather than adjudicated.

All 630 tests green (dune test), 631 with the exhaustive sweep.

Claude-Session: https://claude.ai/code/session_017ZBxCCRM2ojnBupp3SBxV9
</content>
</entry>
<entry>
<title>test(ef): the LMS Ordo as a sixth validation layer</title>
<updated>2026-08-22T10:58:15Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T10:58:15Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=3bfa0c459e3c0b5bfa962b7dbb0227db5a8ba09f'/>
<id>urn:sha1:3bfa0c459e3c0b5bfa962b7dbb0227db5a8ba09f</id>
<content type='text'>
An independent lineage -- neither Divinum Officium, missalemeum nor
lectio -- covering the Mass formulary and the Creed. Characterised
before use, per the discipline the extraordinaryform.org Ordo's
blanket St Lawrence vigil gap taught this session: five opposite-
prediction Creed probes (Sunday/feria, octave-override vs plain
II-class, I-class) all confirmed against the raw extracted text
before a single divergence was adjudicated, recorded in the
fixture's own provenance header.

tools/extract_lms_ordo.ml hand-parses pdftotext -layout output (no
Str/regex, frozen deps) into test/fixtures/lms-ordo-2024-2025.sexp,
400 day-rows (2024-11-27..2025-12-31). Gl/Cr print per Mass-option,
not per day; the extractor takes the first pair in reading order,
which the source's own layout guarantees is the universal entry's,
since a diocesan variant always follows it, never precedes it. The
Ordo's I-V roman numeral ("Missae de sancta Maria in sabbato", RG
309(a)) is matched whole-line only, never by substring -- "V Mass of
BVM" is a substring of "IV Mass of BVM".

test/test_lms_ordo.ml compares two axes 1:1 by date:
  - the Creed (RG 475-476): 399 of 400 days comparable (Good Friday
    has no Mass at all, asserted as the only such day); one genuine
    divergence, adjudicated to the ORDO, not colitur -- All Souls'
    Day 2025-11-03 is a Requiem Mass, and colitur's own creed
    predicate has no notion of one, a pre-existing scope gap
    rubrics_ef.ml already documented in its own header before this
    task existed.
  - the BVM-Saturday seasonal Mass selection, the addendum's own
    "sharper check": all 14 Votive days in the window match their
    season's own numeral exactly, both directions, independently
    re-derived from RG 309(a) rather than calling colitur's private
    function.
  - the formulary override, for the three sources it can honestly
    discriminate (Proper 179, Preceding_sunday 66, Common 2, all
    clean); Own_slug (139) is excluded with evidence, not silently --
    several ferial slugs carry citations byte-identical to their
    Sunday's own, so the Ordo's override line cannot distinguish the
    two representations.

data/ef/expected-divergences-lms.sexp carries the one adjudicated
entry (L1), cited to RG 476(f).

Mutation-tested: inverting RG 475(a)'s Sunday clause reddens 10
existing Rubrics_ef unit tests AND this new layer's own comparator,
independently, on a data source none of the other five layers touch.
Reverted after confirming.

No lib/ changes. day/readings/rubrics output re-confirmed byte-
identical (1583, 2026, 2038, 9999) after this task; all three gates
green (dune test, exhaustive sweep, make check).
</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): a type for which Mass a day says</title>
<updated>2026-08-21T20:18:39Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-21T20:18:39Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=2ac3e3e8fcc66e20bf1687ae15f033d20b02216d'/>
<id>urn:sha1:2ac3e3e8fcc66e20bf1687ae15f033d20b02216d</id>
<content type='text'>
The lectionary's four-step chain already decides whether a day says its own
proper, its own slug's entry, the preceding Sunday's Mass or a Common, and
then discards that decision once the citations are out. An ordo needs to
print it.
</content>
</entry>
<entry>
<title>feat(citation): the Sigla facade, total by construction</title>
<updated>2026-08-20T13:44:29Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T13:44:29Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=987175105ead0ea78b960c0e638a81c6fd2384cf'/>
<id>urn:sha1:987175105ead0ea78b960c0e638a81c6fd2384cf</id>
<content type='text'>
format never raises and returns an unparseable citation unchanged, so a
gap degrades to today's behaviour rather than to a crash. The coverage
test asserts separately that no shipped citation takes that path.

verbatim is what --raw uses: an identity name table would still reformat
punctuation and renumber, which would break byte-exact diffing against
lectio.

The existing citation-coverage walk (1970-2070) now also drives a
round-trip check in the same pass: parse -&gt; render -&gt; parse must reach
the same structure, using Book.default_spelling for names (Book.to_string
returns the internal id, which is not a registered token and cannot be
read back). Proved with a mutation: changing the default style's
part_sep to a separator the parser does not accept reddened the
round-trip case on 31 multi-part citations and nothing else; reverted.
</content>
</entry>
<entry>
<title>feat(citation): render a parsed citation in a configurable style</title>
<updated>2026-08-20T13:09:49Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T13:09:49Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=a2cbb6b85e79fbc59b0879362c0f853757d51c07'/>
<id>urn:sha1:a2cbb6b85e79fbc59b0879362c0f853757d51c07</id>
<content type='text'>
A style is a set of format strings, so punctuation convention is data.

Values are unquoted here rather than in Overlay_ini: that parser trims
every value and is shared with overlays and [defaults], so teaching it
about quotes would change behaviour this feature has no business
changing.
</content>
</entry>
<entry>
<title>test(citation): assert every emitted citation parses</title>
<updated>2026-08-20T13:03:02Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T13:03:02Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=f8c746736fe269ef6e0c4377f58bbb6b1f2fc07a'/>
<id>urn:sha1:f8c746736fe269ef6e0c4377f58bbb6b1f2fc07a</id>
<content type='text'>
Walks 1970-2070 and parses every citation the engine emits. Nothing
validated citation spellings before this, which is why seven books
carried two spellings unnoticed.

Mutation-proved: removing the 'Isa.' spelling from the book table
reddens this test naming that citation.
</content>
</entry>
<entry>
<title>feat(citation): parse citations into structure</title>
<updated>2026-08-20T12:59:03Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-20T12:59:03Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=56e36188c6afc208b96b15b9a1d3d62bbbe2f705'/>
<id>urn:sha1:56e36188c6afc208b96b15b9a1d3d62bbbe2f705</id>
<content type='text'>
The parsed form is a book and a LIST of chapter-parts: the data cites
across chapters and lists disjoint verse ranges within one.

Two rules the shipped data forces and that are not obvious: a
semicolon-separated part may inherit the previous chapter rather than
restate it, and a chapter may be separated from its verses by a comma.
</content>
</entry>
</feed>
