<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/lib/rites/rite_ef/lectionary_ef.ml, branch v1.2.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.2.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v1.2.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-22T11:48:08Z</updated>
<entry>
<title>fix(kernel): Mass_formulary.t.said is honestly optional -- was false for Votive</title>
<updated>2026-08-22T11:48:08Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T11:48:08Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=94ad73cf74d7f1cf02913e2f462c01028a8ef4b4'/>
<id>urn:sha1:94ad73cf74d7f1cf02913e2f462c01028a8ef4b4</id>
<content type='text'>
The .mli promised said is "the slug whose Mass is said". For Votive
(RG 78/309(a), the Saturday votive Mass of Our Lady) it was set to the
day's own ferial slug -- whose Mass is exactly the one NOT said. A
consumer joining rubrics to readings on that slug would silently get
the wrong Mass: 2026-01-03 reports ef-christmas-1-saturday, which has
zero entries in data/ef/lectionary.sexp, because the citations
actually come from bvm_saturday_citations, a season-keyed function
with no slug of its own anywhere in the shipped data.

Chose the type-honest fix over the interim documentation one: said is
now Slug.t option, None exactly for Votive, because there is
genuinely no slug in the shipped data this field could report for
that one source. Adding real ids for the five seasonal BVM Masses
(the reviewer's first option) is out of scope -- a data restructuring
this round explicitly does not carry. Threading the office slug
through a second field was considered and rejected as redundant: the
day's own office is already available on the same Liturgical_day.t
via observed.slug, which every caller already has in scope regardless
of via, so said does not need to duplicate it.

colitur rubrics stays byte-identical: rubrics_line already has
d.observed in scope and falls back to its slug when said is None,
printing the exact value it always printed for a Votive row (verified
directly, diffed against pre-fix output across four years). colitur
day/readings are unaffected (neither reads Mass_formulary at all).

colitur emit --format sexp's pretty-printed line count for 2027 moved
9011 -&gt; 9025: every day's formulary record widened by said's own
extra option wrapping, and to_string_hum wraps by column width.
Cosmetic only, diffed line by line to confirm every change is this
shape or a consequent wrap shift; recorded in test/cli.t alongside the
476(f) note it now sits next to.
</content>
</entry>
<entry>
<title>docs(ef): retract the false LMS Ordo witness claim for Mass_formulary.Votive</title>
<updated>2026-08-22T09:07:07Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-22T09:07:07Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=27b07b447be9cf960d1a44e480d8356245481d17'/>
<id>urn:sha1:27b07b447be9cf960d1a44e480d8356245481d17</id>
<content type='text'>
Fix round 1's own comment claimed the Latin Mass Society Ordo witnesses the
Votive tag directly, reading its "V Mass of BVM" as an abbreviation for
"votive". That was wrong: the Ordo's I-V are roman numerals naming WHICH
of the Missal's five seasonal "Missae de sancta Maria in sabbato" (RG
309(a)'s own "iuxta temporum diversitatem") is said on a given Saturday,
not a marker of the Mass's kind. All five numerals occur through the Ordo
(I x1, II x4, III x3, IV x3, V x8); the false reading came from "V Mass of
BVM" also being a substring of "IV Mass of BVM".

Votive itself is unaffected and stays correct on RG 431(e) alone, quoted
verbatim in its place: "e) in Missis votivis IV classis de Angelis,
quocumque die, et de B. Maria Virg. quae in sabbato celebrantur" -- votive
Masses of the IV class, of the BVM, celebrated on Saturday. The retraction
is recorded, not softened, in lectionary_ef.ml/.mli and the test pin's own
comment, together with what the Ordo's numeral actually means so the
mistake is not repeated, and the consequence it leaves behind: because the
numeral names WHICH seasonal Mass is said, a future comparison against the
Ordo (Task 6) can validate bvm_saturday_citations' own season-keyed
selection, not merely that some BVM Mass was chosen.

Comments and docs only -- no behaviour change. Both suites re-run green and
colitur day re-confirmed byte-identical.
</content>
</entry>
<entry>
<title>fix(kernel,ef): a votive Mass is not the day's own -- add Mass_formulary.Votive</title>
<updated>2026-08-21T20:54:13Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-21T20:54:13Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=28dc226a31fa0cc72432f5607ab5cd74503ef43d'/>
<id>urn:sha1:28dc226a31fa0cc72432f5607ab5cd74503ef43d</id>
<content type='text'>
Mass_formulary.source was missing a case for a Mass said IN PLACE of the
day's own office's Mass while that office is itself kept unchanged -- RG
309(a) and RG 431(e) both classify the RG 78 Saturday Mass of Our Lady this
way, in the Missal's own words, as a "Missa votiva IV classis... de B.
Maria Virg.", not as the day's own office's Mass. The Latin Mass Society
Ordo (docs/research/ordo/lms-ordo-2024-2025.pdf) witnesses it directly,
printing that day as "V Mass of BVM".

The BVM-Saturday branch in Lectionary_ef.readings was tagged Own_slug for
lack of a better constructor when Task 2 landed, flagged there as a
judgement call rather than a specified answer. That call was wrong: left
as Own_slug, a future comparison against the LMS Ordo (a later task in this
plan) would read every BVM Saturday as a manufactured divergence between
colitur's "own" Mass and the Ordo's votive one. Retagged to Votive; said
is unchanged (still the day's own, reused ferial, temporal slug) since the
office itself is unaffected, only the Mass said for it.

Added the new constructor's source_to_string case ("votive") and its own
test row, and pinned the branch itself in test_lectionary_ef.ml's formulary
cases at 1 August 2026, verified directly against the resolver rather than
assumed.

Both this session's own drifted pins that the earlier commit inherited from
the task brief are unaffected by this change, and both are re-confirmed
independently correct in this round: dune test and the exhaustive sweep are
green, and colitur day stays byte-identical against the pre-fix-round
binary.
</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>docs(ef): M13 adjudicated colitur; Mass I is unreachable, not unwitnessed</title>
<updated>2026-08-17T20:30:58Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-17T20:30:58Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=59e78716e5d7b13fd33f9c0245883c83712340e6'/>
<id>urn:sha1:59e78716e5d7b13fd33f9c0245883c83712340e6</id>
<content type='text'>
Two open questions closed, both by looking rather than reasoning.

M13 listed three possibilities for 19 March 2027 and stayed open because
none was confirmed. The live one was (b): a rubric at St Joseph's own
Proprium Sanctorum entry overriding the general table, "the same shape as
the Annunciation's own Attamen clause", its text simply not yet found. It
was looked for directly. Joseph's entry runs from its heading straight
into the Introit with no rubric of any kind -- and the analogue does not
exist where the note placed it either: the Annunciation's entry does the
same. That exception lives in RG 96, a general rubric about transferring
an impeded I-class feast, not in its propers, so there is no precedent
for a propers-level override at all.

With (b) eliminated and (c) still unsupported, (a) stands: RG 91 ranks a
I-class feast above a III-class Passiontide feria, Joseph is not impeded
so RG 96 never engages, and colitur observes him. Recorded with its
limit, because this is elimination and not proof: the specific hypothesis
named is false, which is weaker than showing no rubric anywhere says
otherwise.

Separately, the note that Mass I of the BVM Saturday needed an
Advent-Saturday oracle year to corroborate it is answered: there is no
such year and cannot be. Advent has no IV-class ferias -- Class2 from 17
December, Class3 before -- and RG 78 requires a IV-class feria. Zero
IV-class Advent Saturdays across 2000-2100. Its single witness is not a
gap in the research but the only evidence obtainable. The branch is kept:
the Missal does print the Mass for Advent, RG 309's subject being Masses
that may be celebrated as votive, and an overlay producing such a day
would otherwise fall through silently.

Register: sections 6.13 addendum and 6.14.
</content>
</entry>
<entry>
<title>feat(ef): the votive Mass of Our Lady on Saturday (RG 309(a))</title>
<updated>2026-08-17T19:45:47Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-17T19:45:47Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=cffb879fa124c22acd400f59152a57d20cec036f'/>
<id>urn:sha1:cffb879fa124c22acd400f59152a57d20cec036f</id>
<content type='text'>
RG 78's office has been built since ef-bvm-saturday: an otherwise
unoccupied IV-class Saturday is de sancta Maria in sabbato, white, IV
class. The Mass stayed the feria's, so the day observed Our Lady and then
read Colossians on the parable of the weeds. That is M26 shape 1.

RG 309(a) is the rule -- the Masses the Missal assigns "iuxta temporum
diversitatem" -- and it prints five, each under its own season heading.
All ten citations are transcribed from the scans with line numbers in the
source. Masses II-V were confirmed twice, against the scan and against a
live missalemeum capture of 2038 which names them and agrees on both
readings. Mass I rests on the scan alone: no oracle year to hand has an
Advent Saturday carrying this office. One witness where the others have
two, and the code says so rather than blurring it.

The mapping looked like the hard part and dissolved. The Missal's ranges
are cut by civil dates and movable feasts, not by this rite's seasons --
II ends mid-season at the Purification, III spans four seasons. But
measured against what a IV-class Saturday can actually be, it reduces to
a seasonal mapping plus one date test at 2/3 February, with no Easter
arithmetic at all: III's end to IV's start leaves the Triduum unassigned,
unreachable because Holy Saturday is I class; IV's end to V's start
leaves Pentecost week unassigned, also unreachable because that week's
Saturday is an Ember Saturday. Time after Pentecost then begins exactly
at Trinity, exactly where Mass V begins. Both gaps verified by sweep --
zero IV-class Saturdays in either across 2000-2059 -- not inferred.

The office is identified structurally, never off the slug, which it
deliberately shares with the ordinary feria: subject Bvm, IV class,
Saturday.

Blast radius: 87611 reading rows over the full domain, every one a
Saturday.

Allow-lists: M26 27 to 6, shape 1 gone, leaving only the Christ-the-King
residue argued in colitur's favour last commit. The 2038 suite's
BVM-SATURDAY-MASS class is removed rather than zeroed -- an id with no
rows must not be declared. M18 355 to 376. C17 widened 397 to 445,
taking its own Saturdays back from C1, C19 and C25, since one cause
should not be filed under two ids; C31 89 to 103; C25 closed at 0 rows,
its Holy-Name-week Saturdays now answered before step 3 is reached.

Three unit tests pinned the old behaviour and are corrected rather than
re-pinned: two asserted the day "keeps its ferial Mass", which was the
honest thing to assert while this was unimplemented. The third still
tests what it always did -- that step 4 refuses a temporal office -- and
only what answers instead has changed.

Register: section 6.13.
</content>
</entry>
<entry>
<title>ef(lectionary): fix round 1 -- the step-4 guard, and a miscited authority</title>
<updated>2026-08-14T23:59:11Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T23:59:11Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=6b41415f17f3264454f6dcc13898948fd1902d0b'/>
<id>urn:sha1:6b41415f17f3264454f6dcc13898948fd1902d0b</id>
<content type='text'>
Review re-verified all fifteen saints and all seven formularies against both
printings and found zero citation discrepancies, confirming the Gabriel
printing error and all three proper/Common reversals; the reordering was
adjudicated sound. Two Important findings, both about the guard rather than
the data.

IMPORTANT 1 -- the guard had no test, and a comment claimed it did.
`test_step4_never_diverts_a_temporal_office` asserted 2026-07-04 keeps its
ferial Mass and its comment claimed to "pin it behaviourally". It did not:
no shipped assignment names a temporal slug, so the guard is a NO-OP on
shipped data and that test passes with the guard removed. The reviewer
proved it by forcing `sanctoral_office = true` -- all 357 tests stayed
green. That mattered more than an ordinary missing test: the guard is the
structural claim the whole reordering argument leans on, and on a task with
no oracle the tests are the entire safety net.

Fixed by exposing `Commons.of_tables` (already present internally; it
applies exactly `load`'s validation, so a synthetic table is a well-formed
table with a WRONG assignment rather than malformed data the loader would
reject before the guard is reached -- and it is the constructor a future
diocesan overlay needs anyway), adding `day_with ~commons` beside `day`, and
writing test_step4_guard_refuses_a_common_assigned_to_a_ferial_slug: a
synthetic Commons assigning the Common of Abbots to
`ef-time-after-pentecost-5-saturday`, a really-observed ferial slug,
asserting 2026-07-04 still says its ferial Mass. Two checks, the first
making the second mean something -- it asserts the hostile assignment IS
present and resolvable, so the ferial Mass wins because the GUARD refused it
and not because the lookup missed. Mutation-verified: with the guard
disabled exactly one test fails, this one; before this round that mutation
reddened nothing. The old test is renamed
test_step4_leaves_a_temporal_office_alone_on_shipped_data and its comment
corrected to say it does not pin the guard.

IMPORTANT 2 -- the guard cited an authority that does not say what was
claimed. The comment said "[Validate] already asserts slug uniqueness per
liturgical year, so a sanctoral feast can never collide with a temporal
slug". validate.ml's check maps over `Temporal.office` slugs ONLY, compared
to each other across the days of one year; it says nothing about
cross-stream collision. An assumption was promoted to an asserted invariant
-- the exact defect class this project's citation discipline exists to
catch. Rewritten to state it as an assumption (no sanctoral slug carries the
`ef-` prefix every temporal slug does; 0 of 327 today), to quote the real
authority verbatim (validate.ml's own note that this "is the same assumption
the rest of this codebase already leans on"), to carry a CORRECTED marker
naming the wrong citation so it is not re-derived, and to record the failure
mode if it ever broke: benign and one-directional -- a colliding saint is
denied his Common and falls through to steps 2/3, i.e. to exactly the answer
the unguarded chain would have given him. No day gains a reading it should
not have.

MINOR -- the previous commit body led with "Blast radius, measured ... ZERO
differing lines", which is true but oversold: the CLI prints no citations, so
that sweep is STRUCTURALLY INCAPABLE of observing the reorder or any citation
value. It is a valid negative control for the sanctoral `Edit` overlay and
nothing else. The evidence for the reorder is mutation 1 (relegating step 4
to last reddens exactly the four step-4 pins) plus those pins' own explicit
expected values -- not the sweep. Correcting the record here.

MINOR -- test_commons_load_rejects_bad_data wrote four FIXED-name files into
the temp dir and removed none, colliding across concurrent runs. Replaced
with a local `with_temp_file` copied from test_lectionary.ml's own
(`Filename.temp_file` + `Fun.protect ~finally`); the four labels moved into
the assertion messages where they belonged. Verified zero leftovers after a
full run.

MINOR -- added the sharper argument for the reorder, which makes the
deviation obviously right rather than merely well-evidenced, and it now LEADS
the branch comment as warrant (1), with the Missal citation demoted to a
corroborating warrant (2): step 4 is STEP 1'S CONTINUATION. Step 1 already
runs the observed office's own proper ahead of steps 2 and 3; step 4 is that
same rule for the saints whose readings the Missal keeps in a Common instead
of printing on the celebration. Placing it last would have made the chain
internally inconsistent with code that already existed -- St Joseph beating a
competing temporal entry because his readings sit on his Celebration.t, and
St Vincent Ferrer losing to one because his sit one indirection away. Nothing
in the rubrics draws that distinction; it is an artefact of where colitur
stores the data. So the plan's ordering did not merely disagree with the
data, it contradicted step 1.

358 tests green (357 before), 359 with the exhaustive sweep.
</content>
</entry>
<entry>
<title>ef(lectionary): the Commons, chain step 4</title>
<updated>2026-08-14T23:40:54Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T23:40:54Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=1299815ea03c2b1e4ff19d92d32e386fec24f4e4'/>
<id>urn:sha1:1299815ea03c2b1e4ff19d92d32e386fec24f4e4</id>
<content type='text'>
Fifteen class-3 saints had no readings anywhere in colitur -- the 6 March -
5 April cluster whose RANKS lectio's generator fix of 2026-08-12 restored
without backfilling readings, and lectio has no Commons concept to have
backfilled them from. They are exactly the fifteen `status Feast` entries in
data/ef/sanctoral.sexp carrying `(citations ())`.

The Missal splits them eight/seven, and NOT as the plan predicted. It
expected propers for Benedict, Patrick, Thomas Aquinas and Gregory the
Great; only Thomas Aquinas has one. Benedict ("Missa Os iusti, de Communi
Abbatum"), Patrick ("Missa Statuit, de Communi Confessoris Pontificis I
loco") and Gregory the Great ("Missa Si diligis me, de Communi unius aut
plurium Summorum Pontificum") are all sent to a Common, with only Oratio,
Secreta and Postcommunio printed at the date. All three reversals verified
on the page images (pp. 488, 492) as well as in both OCR text layers.

PROPERS (data/ef/adjustments.sexp, `Edit ... Set_citation`):
  thomas-aquinas         7 Mar  Sap 7:7-14      / Mt 5:13-19
  john-of-god            8 Mar  Eccli 31:8-11   / Mt 22:34-46
  forty-holy-martyrs    10 Mar  Hebr 11:33-39   / Luc 6:17-23
  cyril-of-jerusalem    18 Mar  Eccli 39:6-14   / Mt 10:23-28
  gabriel-the-archangel 24 Mar  Dan 9:21-26     / Luc 1:26-38
  john-damascene        27 Mar  Sap 10:10-17    / Luc 6:6-11
  john-of-capistrano    28 Mar  Sap 10:10-14    / Luc 9:1-6
  francis-of-paola       2 Apr  Philipp 3:7-12  / Luc 12:32-34

COMMONS (data/ef/commons.sexp), each quoting the Missal's own instruction at
the saint's date:
  sts-felicitas-perpetua  6 Mar  non Virginum I   Eccli 51:1-8,12 / Mt 13:44-52
  frances-rome            9 Mar  non Virginum II  Prov 31:10-31   / Mt 13:44-52
  gregory-the-great      12 Mar  Summ. Pontificum 1 Petri 5:1-4,10-11 / Mt 16:13-19
  patrick                17 Mar  Conf. Pont. I    Eccli 44:16-27;45:3-20 / Mt 25:14-23
  benedict               21 Mar  Abbatum          Eccli 45:1-6    / Mt 19:27-29
  isidore-of-seville      4 Apr  Doctorum         2 Tim 4:1-8     / Mt 5:13-19
  vincent-ferrer          5 Apr  Conf. non Pont. I Eccli 31:8-11  / Luc 12:35-40

Every value read in three independent places -- both OCR text layers (two
DIFFERENT printings, whose Commune Sanctorum pagination differs by 1-2, so
the data keys on heading plus Mass incipit and never on the bracketed page
number) and the rendered page images. That caught a genuine typographical
error in one printing: it gives St Gabriel's Gospel as "Luc. 2, 26-38" (on
the page image, so not an OCR artefact). Luke 1:26-38 is settled by the
other printing, by the pericope text in both, and by the SAME edition citing
the identical pericope correctly two pages later at the Annunciation.

Step 4 EXECUTES SECOND (order 1, 4, 2, 3), not last as the plan sketched.
Measured: every day on which one of the fifteen is actually the observed
office already has a non-empty step-2 or step-3 answer waiting, so a step 4
placed after the ferial fallback is unreachable on every date in 1583-9999 --
and wrong where it would fire (2038-03-06 would emit Septuagesima II
Saturday's Mass on a day whose office is Sts Perpetua and Felicity). Step 4
is also the only step in the chain with a direct primary-source warrant: the
Missal names the Mass at each such saint's own date, while steps 2 and 3 rest
only on lectio's observed behaviour. Guarded so it can never divert a day
whose observed office IS its temporal office -- ferias, Sundays, the Triduum
and the RG 78 Saturday Office of the BVM (which deliberately shares the
ferial slug) are structurally excluded. Step NUMBERS are unchanged so every
"step 3" already written down still names the same branch.

The Commons are caller-supplied, like the lectionary: `Rite_ef.context` gains
a REQUIRED `~commons`, not an optional one -- a silently-defaulted empty
table would give a rite whose class-3 saints quietly lose their Mass, and
nothing in layers 3-5 compares citations, so that loss would be invisible.
`Commons.load` rejects the four defects indistinguishable downstream from
"this saint has no Common": duplicate common id, duplicate assignment, empty
formulary, assignment naming a common that does not exist.

KNOWN LIMITS, recorded rather than papered over. There is no oracle: lectio
has no readings for these feasts and missalemeum's 2026-2027 window never
observes one of the fifteen. Eight of the fifteen are NEVER the observed
office anywhere in the domain (10-28 March always falls to a Lenten or
Passiontide feria that outranks a III-class feast), so they have no
end-to-end witness and are covered by dedicated table tests instead. The
Commune Sanctorum's own opening rubric permits any Epistle or Gospel of a
Common in any Mass of that Common unless one is assigned, so what is emitted
is the reading PRINTED WITH the named formulary, not the only lawful one;
labelled alternatives (e.g. the widow's Epistle 1 Tim 5:3-10, squarely
available to St Frances of Rome) are noted in the data and deliberately not
encoded. The BVM Common is NOT authored: the RG 78 Saturday Office shares the
ordinary ferial slug, so assigning a Common to it would hand the BVM Mass to
every feria sharing that slug; routing it needs a subject-keyed lookup and a
season-keyed choice among the Missal's five "Missae de sancta Maria in
sabbato" -- new behaviour, not new data. It currently emits its feria's Mass,
now pinned as such.

Blast radius, measured (git archive HEAD binary vs HEAD, full 1583-9999
`colitur day` sweep, diffed): ZERO differing lines, 3 074 246 lines each
side, byte-identical -- the CLI prints no citations, so this change is
invisible to layers 2-5 by construction, and the sanctoral overlay perturbed
nothing else.

357 tests green (344 before), 358 with the exhaustive sweep. Mutation-tested
six ways, all reverted after confirming: relegating step 4 to last reddens
exactly the four step-4 pins and nothing else; corrupting a Common's citation,
dropping an assignment, dropping a proper Edit, and corrupting either an
unreachable proper or an unreachable Common each redden their own pins. The
load-bearing assertion is stated over the loaded layer rather than a
hard-coded list: every sanctoral entry that can ever BE the observed office
now has either a proper or an assigned Common -- fifteen failures before,
zero after, and a future re-bootstrap adding a readingless class-3 feast
fails there instead of silently emitting its feria's Mass.
</content>
</entry>
<entry>
<title>ef(lectionary): fix round 1 -- correct a wrong test, a wrong comment, and ba0adba's own wrong commit body</title>
<updated>2026-08-14T23:06:20Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T23:06:20Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=fe94cd9c4150fd6285dab49b06e23b6db42d131b'/>
<id>urn:sha1:fe94cd9c4150fd6285dab49b06e23b6db42d131b</id>
<content type='text'>
Three Important findings, all traceable to the task-5 brief rather than
the implementation itself; all confirmed against the real data and the
real resolver before fixing, not taken on trust.

1. test_step3_uses_temporal_not_observed (2028-12-26) did not exercise
   step 3 at all: 26 December is always Stephen, a real sanctoral entry
   with its own citations, so that date resolves entirely at step 1.
   Its justifying comment was also wrong -- 24 December's TEMPORAL slug
   is ef-nativity-vigil, IDENTICAL to its observed slug (Temporal_ef.named
   hard-codes the Vigil for that date ahead of any Sunday computation),
   so there was never a temporal/observed split on that date to exploit.
   Replaced with 2025-02-03: 2 February 2025 (Sunday) is observed as the
   Purification (own citations Mal 3:1-4 / Luke 2:22-32) but its TEMPORAL
   identity is ef-time-after-epiphany-sunday-4 (Rom 13:8-10 / Matt
   8:23-27, a different lectionary entry); 3 February has no proper of
   its own and reaches step 3, which must return the Sunday's TEMPORAL
   reading, not the Purification's. Verified against
   data/ef/sanctoral.sexp and data/ef/lectionary.sexp directly.

2. The termination-argument comment in lectionary_ef.ml (and its echo in
   lectionary_ef.mli) claimed an unguarded Sunday would loop. It would
   not: readings is not recursive -- step 3's fallback is one flat
   Lectionary.find, never a re-entrant call into readings -- so an
   unguarded Sunday would just repeat step 2's own already-failed lookup
   once (same pure inputs, same None) and return [] normally. Rewritten
   to say what is actually true: the guard exists because a Sunday has
   no PRECEDING Sunday to resume, not because skipping it would be
   dangerous; the chain terminates because every step consults data or a
   strictly earlier date, and no step ever calls back into readings.

3. Correcting the record, per instruction, rather than amending
   ba0adba: that commit's own body said Advent ferias carry 'Advent I's
   own readings copied onto the following Monday-Thursday'. Both details
   are wrong, verified directly against data/ef/lectionary.sexp: the
   duplicated readings are ef-advent-SUNDAY-2's (Rom 15:4-13 / Matt
   11:2-10), not Advent I's, and they appear on ef-advent-2-monday,
   -tuesday, -thursday and -saturday -- four non-contiguous days, not a
   Monday-to-Thursday span. The in-code comment and the task-5 brief's
   own commit template both already said 'Advent II' correctly; only
   ba0adba's commit body had the error.

dune test --force: 344 tests, all green (unchanged count -- one test's
body changed, none added or removed).
</content>
</entry>
<entry>
<title>ef(lectionary): a feria says the preceding Sunday's Mass</title>
<updated>2026-08-14T22:50:16Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-14T22:50:16Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=ba0adbaf3176ff753312d7052d0dc2795ac55dc9'/>
<id>urn:sha1:ba0adbaf3176ff753312d7052d0dc2795ac55dc9</id>
<content type='text'>
Chain step 3. Guarded on weekday &lt;&gt; Sun: a Sunday reaching this branch
would look up its own slug via days_since_sunday Sun = 0 and loop --
every other chain step consults data, this one consults a strictly
earlier date, so that guard is the whole chain's termination argument.
Reaches the Sunday by Date.add_days plus a fresh temporal_at call, never
by string surgery on the day's own slug -- the slug shapes are genuinely
inconsistent across seasons (ef-advent-sunday-1 vs ef-advent-1-monday,
week number on opposite sides of the season name).

Uses the preceding Sunday's TEMPORAL slug, never its observed one: the
rubric is the preceding Sunday's Mass even in a year a feast displaced
that Sunday from being observed (pinned: 2028-12-26, the Monday after a
Vigil-displaced Advent IV Sunday, still takes Advent IV's Mass).

Measured over the full 1583-9999 domain (temporal cycle only, no
sanctoral contest): of 412 distinct temporal slugs, 305 carry no
lectionary entry of their own; of the 304 that are feria (non-Sunday)
slugs, step 3 alone resolves 297 of them via their preceding Sunday.
The 7 that remain, plus the 1 uncovered Sunday slug itself
(ef-holy-name-sunday), all trace to the same two missing lectionary
entries (Holy Name Sunday and 30 December), not to eight independent
gaps or a step-3 defect -- traced date-by-date, not merely counted.
Day-level effect, 2005-2050 (full Precedence+Calendar pipeline,
matching this project's existing differential window): 16807 days,
16531 resolved (98.36%), 276 still empty; step 3 alone accounts for
4503 of the resolved days, more than either step 1 or step 2.

Warrant is the same class as step 2's, not a confirmed Missal
citation: lectio hard-codes this shape as literal duplicated data on
the four Advent ferias (Advent I's own readings copied onto the
following Monday-Thursday) and leaves the rest of that same shape
simply absent; step 3 turns the duplication into a rule.

dune test --force: 344 tests, all green (was 340).
</content>
</entry>
</feed>
