| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
--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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
| |
A second rite is new functionality that breaks nothing: EF output is
byte-identical to v1.0.0, no flag was removed, and emit --format csv's
seventeenth column appears only under --rite of. Minor bump, not major.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
An audit probed every flag against every command rather than reading --help,
and found three inconsistencies.
--rite reached only `day` and `readings`. main.ml's own comment gave the
reason -- "has not been widened to a second rite in this task" -- a scope note
that had outlived its task and hardened into apparent design. View.of_days was
already polymorphic over the rite's type parameters, so widening was plumbing,
not library work: `temporal`, `rubrics`, `emit`, `table`, `render` and
`publish` now all take it.
`temporal` was the sharpest case. Its refusal said "--rite has no effect on
`temporal`", which was false: the EF has Septuagesima and Passiontide, the OF
neither, and every EF slug is ef-prefixed, so the flag would change nearly
every line. A message claiming no effect where the effect is total is exactly
what the audit set out to find.
Three ways of naming a year (positional, --year, --from/--to) now cross-accept
additively; naming two that disagree is a usage error rather than one silently
winning.
emit --format csv gained a rite-dependent header: EF's 16 columns are
unchanged, OF gets a 17th "second" between "first" and "gospel". An earlier
task had recorded RFC 4180 as permanently blocking this; the rule constrains
one file, not a family of them.
`rubrics` keeps refusing --lang/--raw, now with its reason. An intermediate
version accepted them by adding a name column, which changed the default from
six tab-separated fields to seven and broke both existing consumers and the
byte-identical-EF rule. The asymmetry is real but principled: the row is a
date, a slug, a source keyword, two booleans and a preface key, so there is
nothing to translate and nothing to strip. `easter` refuses --rite for the
same kind of reason -- its six anchors sit at identical Easter offsets in both
rites.
EF output verified byte-identical to 8590338 across day, readings, rubrics,
temporal and easter for 2026, 1583 and 9999, and across all five emit formats.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
CLAUDE.md's own Current state still read 'Plans 1-3 + the EF lectionary DONE'
and listed the OF module as future work, so the orientation doc a fresh
session reads first did not know the rite exists.
Records what the OF's three validation layers cannot see -- no published-ordo
witness at all where EF has three, identity comparison reaching ~12% of rows,
Validate.run being blind to value-level misplacement, and an allow-list entry
having twice hidden a real defect -- and scopes the six-layer Validation
section to EF, which is the only rite it describes.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
precedence_of.ml's transfer_target Rule 1 (Normae n. 60's fixed Easter+8
destination for the Annunciation falling in Holy Week) keyed off
"of-annunciation", a placeholder that never matched the real shipped
entry's own slug ("annunciation-of-the-lord",
data/of/calendar-2002.sexp). Rule 1 was therefore dead code: it could
only ever fire against test_precedence_of.ml's own synthetic candidate,
which happened to carry the identical placeholder.
Output was nonetheless correct on shipped data (latent, not live): Rule
3's general forward search structurally converges on the same Easter+8
target, because the Easter Octave occupies exactly Easter+1..+7 at band
20 and the 3-9 April window carries only memorials on the universal
calendar. The exposure is an overlay placing a proper solemnity (band
40) or proper feast (band 80) anywhere in 3-9 April, where Rule 3 would
diverge from Rule 1's fixed destination and Rule 1 would silently fail
to override it.
Fixed the slug, and updated the existing Rule-1 tests' own synthetic
candidate to the real slug so they keep exercising Rule 1 rather than
Rule 3's coincidental agreement. Added a test that tells the two rules
apart rather than only checking the output they happen to agree on: it
rigs the occupant callback to occupy Easter+8 with a synthetic
Tabula-entry-3 candidate, confirms (via a control case using a
different solemnity) that the rig genuinely forces Rule 3's search past
that date, then shows the real shipped Annunciation still lands on
Easter+8 despite the block -- only explicable by Rule 1 firing, not by
Rule 3 happening to agree.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Mary, Mother of the Church (Easter+50) and the Immaculate Heart of Mary
(Easter+69) are both movable obligatory memorials that can land on a
FIXED obligatory memorial's own date -- e.g. 2011-06-13 and 2015-06-13,
both against Anthony of Padua. Both candidates banded identically at
Tabula III.10 (100, both universal Memoria_obligatoria), a tie band
could not break, so Precedence.resolve's kernel-level alphabetical
Slug.compare tie-break silently picked instead -- 892 days for Mater
Ecclesiae and 1109 for the Immaculate Heart across 1583-9999, all one
shape (measured against the pre-fix alphabetical order directly, zero
unexplained).
Searched the corpus rather than inventing a rule. colitur's two
previously-checked primary sources really are silent: the 2018 decree
(AAS 110, 437-438) never addresses universal-calendar coincidence, and
Normae n. 14's third clause resolves only two AD-LIBITUM memorials
colliding. A third source resolves it: the CDWDS's own "Notification on
the Memorial of the Blessed Virgin Mary, Mother of the Church" (24 March
2018 -- same dicastery and signatories as the decree; published only on
vatican.va, confirmed absent from the AAS 2018 combined index) states
that when this memorial "coincides with another Memorial of a Saint or
Blessed... the Memorial of the Blessed Virgin Mary is to prevail," and
extends the identical reasoning to the Immaculate Heart of Mary by name.
This is a rubric, not colitur's own reasoned choice.
Implemented as a sub-rank of 95, strictly between Tabula entries 9 and
10 -- the same "fits between neighbours" technique this module already
uses elsewhere -- scoped to the two named slugs rather than
[subject = Bvm], since the Notification's own reasoning is specifically
about a memorial's link to a movable solemnity of the Lord, not a
blanket Marian precedence.
Golden pin updated: test_rite_of.ml's 2011-06-13 tie now pins Mary,
Mother of the Church as observed (was Anthony of Padua, labelled "known
arbitrary"), with the header rewritten to state the outcome now rests on
the Notification, not a coin-flip. The litcal oracle allow-list gains
L10: litcal's own grade vocabulary has no representation for a 95
sub-rank (everything Memoria_obligatoria reads "Memorial"), a
representational gap in litcal, not a computational disagreement -- the
identity axis is untouched and needed no new entry.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
lib/render/view.ml hardcoded exactly two template keys, "first" and
"gospel", regardless of what a day's citations actually contain. The OF
now resolves a third reading, Second, on Sundays and solemnities (OLM
1981 Praenotanda n. 69.1/n. 84(b)(c)) via the rite-supplied
Rite.t.citation_shapes, which the render layer could not express. Latent
today (bin/main.ml's reject_rite_for refuses --rite on every command that
reaches View.of_days, so only EF ever reaches this path), but the wrong
shape to carry forward.
View.citation_fields now derives one key per Citation.part ACTUALLY
PRESENT in a day's own citations, in Citation.all_parts order, using
Citation.part_to_string for the key name. An absent part contributes no
key at all, not a key holding the empty string: Template.render already
treats a missing key and a present Str "" identically in Var, Section and
Inverted position, so nothing is lost, and Emit_json.year dumps the whole
Obj verbatim, so an unconditionally-present-but-empty key for a
still-unbuilt part (Psalm/Tract/Alleluia/Sequence) would sit in every EF
day's JSON forever. Filtering to present parts alone is what makes EF's
output identical byte for byte BY CONSTRUCTION rather than by a rite
check: EF's citations are always exactly [First; Gospel], so the derived
key set is always {"first"; "gospel"}, in that order.
padding_cell keeps its own fixed "first"/"gospel" pair rather than
deriving from a (nonexistent) day: it mirrors the closed set every rite
currently reachable through this render path (EF alone) always carries,
documented as debt for whenever a rite whose citation_shapes includes
Second is admitted here -- test_padding_and_real_share_key_set would
catch the mismatch immediately.
Downstream consumers: Emit_json needed no change (already a verbatim
dump). Emit_xml and Emit_ics gained a third, order-preserving element/line
(a <citation part="second"> element; a "Second ..." DESCRIPTION line
spliced between Epistle and Gospel) since neither is a fixed-column
format. Emit_csv is deliberately left unwidened and commented: RFC 4180's
header-row contract makes a variable column count illegal, and OF cannot
reach `emit` today regardless, so there is nothing to widen for yet;
admitting OF here later needs a disclosed, deliberate format change, not
a silent one.
term_keys (line ~239) is left unchanged, with a comment recording the
judgment call: "epistle" and "lesson" are indeed EF/Roman vocabulary
(Epistola vs. a non-apostolic Lectio, e.g. an Ember day's Old Testament
reading) sitting in an otherwise rite-agnostic list, but nothing forces a
fix yet -- no OF template exists, and every in-repo EF template already
reads term.epistle, so renaming it would break 11 shipped templates and
any user template for zero present benefit. "lesson" already sits unused,
already translated in both lang files, and is the natural neutral term a
future OF ordo template would reach for.
Tests: test_view.ml gains test_ef_days_never_carry_a_second_key (a whole
year, not one day) and test_three_citation_day_exposes_all_three, driving
View.of_days directly with a hand-built Liturgical_day.t since OF cannot
reach this path through the CLI yet -- the only honest way to exercise a
latent path. test_emit.ml/test_ics.ml extend coverage to Emit_xml/Emit_ics
(presence, value, and reading order) and pin Emit_csv's deliberate
16-column non-widening.
EF byte-identity: zero diff in data/ef/ or lib/rites/rite_ef/ against the
pre-change commit. `colitur day`, `readings`, `emit --format csv/xml/json/
ics`, and `table --template templates/ef/ordo.txt` for 2026, all non-empty,
all byte-identical (cmp) against a worktree build of the pre-change commit.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Parse.verse_range's [last] endpoint gains an optional chapter
(Parse.verse_end: { chapter : int option; verse : verse_num }), so a
hyphen range whose two endpoints lie in different chapters
("1 John 1:5-2:2") can be represented at all. Rejected: a bare
[int option] living alongside [last] as a second field on
verse_range -- that would let 'a chapter with no verse' exist as a
constructible value.
parse_part now splits a part's leading "chapter:" at the FIRST
colon only (not every colon), so the verses side can itself carry a
second colon from a crossing range. parse_range detects a crossing
by checking whether the range's right-hand side contains ':', and
skips the same-chapter descending-range guard for that case (a later
chapter is always "ahead", whatever its own verse numbers are).
Handles the compound shape too -- a crossing range followed by
further, same-chapter verse references in the same comma list
("Matthew 9:35-10:1,5a,6-8") -- since those trailing pieces parse as
ordinary bare verses/ranges, unaffected by the preceding crossing.
Render's one_range renders a crossing [last] through the same
chapter_verse template one_part already uses for the part's own
leading "chapter:verses", so a style that reconfigures the
chapter/verse separator renders a crossing endpoint in that same
convention rather than a hardcoded ':'.
This closes the W4 known-wrong: 41 (now 49, after an intervening
Second-reading extraction) of the OF lectionary's citations printed
unconverted, every one this exact shape. test_citation_coverage_of.ml's
pinned residual is now empty and asserted exactly, over the full
1725-field data/of/lectionary.sexp population, including the round-trip
check (parse -> render -> parse structural equality). test_citation.ml
gains direct parse-suite cases for the basic crossing, the compound
shape, a mid-list crossing, a crossing with a sub-verse letter, and a
malformed-crossing rejection.
data/of/lectionary.sexp is regenerated via its own generator
(tools/bootstrap_lectionary_of.ml, whose own embedded header text is
updated to match); only comment lines change, confirmed by diff --
no lectionary entry differs. test_lectionary_of.ml's whole-file
SHA-256 pin is updated to match.
EF is unaffected: data/ef/ is untouched since v1.0.0, and a direct
byte comparison of `colitur day`/`colitur readings` for 2026, 1583
and 9999 against a git-worktree build of 1c0137d is identical on all
six outputs.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
temporal_of.ml's temporal only ever reached holy_family's own correct
26-31 December / 30 December fallback logic through sunday_slug, which
returns None immediately for a non-Sunday date. In a year 25 December
is itself a Sunday (26-31 December then holding no Sunday of its own),
the feast vanished entirely and fell through to an ordinary Christmas
ferial slug -- confirmed on 2022, 2033, 2039, 2044, 2050 (and roughly
1583..9999 domain-wide, one year in seven).
temporal's dispatch now consults holy_family directly, independent of
weekday, between the sunday_slug and christmas_feria_slug branches,
carrying the identical identity the Sunday case already builds
(subject Lord, holy_family_names, rank Festum). holy_family and
anchors were already correct and needed no change.
Added a direct example-based test for the fallback across five
affected years plus a control for the unaffected Sunday case, and a
domain-wide property (Holy Family is observed in every liturgical
year 1583-9999) folded into both the 200-sample QCheck run and the
exhaustive sweep -- the property that would have caught this directly.
Un-pinned the now-fixed behaviour everywhere it was recorded as
known-wrong: test_rite_of.ml's own 1583 pin (rewritten to assert the
fix), test_validate_of.ml's own independent exhaustive-sweep counter
and landmark-year filter (found via make check, not the initial
survey), and data/of/expected-divergences-litcal.sexp's L2/L3
allow-list entries against the litcal oracle (closed and removed, with
a dedicated regression test replacing the allow-list's own silence).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 <> 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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The OF lectionary (data/of/lectionary.sexp) carries 183 Second readings,
146 of them on Sunday keys, and the kernel resolves them correctly -- but
readings_line (EF) and readings_line_of (OF) in bin/main.ml only ever
printed Citation.First and Citation.Gospel, so `colitur readings --rite of`
silently dropped every Second reading it computed.
Both functions gain a second_suffix lookup, spliced between the existing
First and Gospel fields, present only when the day carries a Second
citation. No rite check: EF's citation_shapes is [[First; Gospel]] alone,
so EF rows are unaffected by construction, not by special-casing.
EF byte-identity verified two ways: `git diff --stat v1.0.0..HEAD --
data/ef/` is empty, and `colitur day`/`colitur readings --rite ef` for
2026, 1583 and 9999 cmp identical against a build of the prior commit.
test/cli.t: fixed the one now-stale assertion and added coverage for the
three-citation OF Sunday shape alongside the unchanged two-citation OF
weekday and EF shapes.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 -> 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 -> 49, all new
entries the same already-understood chapter-crossing shape.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
README.md said "lib/rites/ contains rite_ef and nothing else" and
"treat any claim of multi-rite support as a design goal rather than a
feature" -- false as of this branch: lib/rites/ also contains rite_of,
wired into a working --rite of. Rewrite the opening paragraph to state
what actually ships, with the OF's own honest limits relative to the
EF's (no published-ordo witness, Polish-vernacular lectionary lineage,
known-wrong pinned dates, First reading + Gospel only).
Also fixes two further stale numbers this same paragraph's neighbours
carried, unrelated to this branch's own content but caught while here:
"dune test # fast suite, 568 tests" (actual: 887) and "## Status"'s
"v0.9.0, EF only. 569 tests" (actual tag: v1.0.0; this line is written
from an unreleased branch, stated as such rather than inventing a
version number).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
colitur readings --rite of printed "- | -" on 25 December every year
-- lectio's own 988 keys never included the Christmas DAY Mass at
all, only the Vigil (already correctly noted, but left unfilled, in
tools/bootstrap_lectionary_of.ml's own named_overrides comment).
Sourced, not guessed: docs/research/of/olm-1981-ocr.txt:4513-4520,
"16 Ad Missam in die", the same primary authority this module already
cites for the cycle rules. First reading and Gospel only, matching
this file's own scope everywhere else (First/Gospel is the kernel's
own boundary, I7, a separate deferred task) -- Isaiah 52:7-10 / John
1:1-18 (OLM's own LONGER form; the file's LINEAGE section already
discloses that short/long-form choices are not modelled anywhere in
this data, so this is an application of an existing limitation, not a
new one).
Injected via a new hand_authored table in the generator, merged into
entries before assert_reachable/Lectionary.of_entries -- there is no
ini section to derive this from. One new lookup_any call (readings'
own existing temporal-slug fallback, unmodified) now resolves BOTH the
formulary and the citations for 25 December from the same entry, so
both halves of the "citations-unresolved"/"formulary" gap close
together, not just the citation half.
Verified across the WHOLE domain, not assumed: test_validate_of.ml's
exhaustive sweep (COLITUR_EXHAUSTIVE_SWEEP=1, all 8 416 years) now
asserts the Nativity gap fires on NONE of them, down from all 8 416
before this fix -- and is kept as a live, dedicated "must never recur"
counter rather than deleted. test_rite_of.ml's landmark-year check and
test_lectionary_of.ml's 2026 coverage pins are updated the same way
(the unresolved-day set that used to be pinned as {25 December} is now
pinned as empty, not merely a count going to zero). A concrete golden
pin (test_golden_of.ml) locks the exact citations through the full
resolved pipeline. data/of/lectionary.sexp regenerated (771 entries,
was 770); its own SHA-256 re-pinned.
make check (COLITUR_EXHAUSTIVE_SWEEP=1 dune test --force, unpiped,
foreground): exit 0, 895 tests, ~536s.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fix option (c) from the I2 review finding, done alongside the parser
fix itself rather than deferred: tools/bootstrap_lectionary_of.ml now
runs every emitted reference through Colitur_citation.Parse.parse at
generation time and adds a fourth COVERAGE item plus a named listing
to data/of/lectionary.sexp's own header, so the 41-reference residual
(all chapter-crossing hyphen ranges, see the citation-fix commit) is
disclosed in the artifact a reader actually opens, not only in a task
report or test file.
Regenerated against the pinned lectio snapshot (dune exec
tools/bootstrap_lectionary_of.exe -- ../lectio/internal/caldata/
of-lectionary.ini data/of/lectionary.sexp); diffed against the
pre-change file to confirm the change is header-only, zero lines
removed, the sexp payload byte-identical. Re-pins the file's own
SHA-256 in test_lectionary_of.ml accordingly (re-derived with
sha256sum, not transcribed from generator stdout, matching that
test's own stated discipline).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
35% of OF citation fields (259/730 on colitur readings --rite of 2026)
printed unconverted -- 1 John renders on 2 January but not 3 January.
Two independent causes, both in the citation/siglum path, neither in
the OF data itself:
1. Book.table only ever surveyed the three EF citation-bearing files,
so 345 references citing a book no EF file happens to use (Job,
Ruth, Judges, 1/2 Samuel, 1/2 Chronicles, 1/2 Maccabees, Baruch,
Ecclesiastes, Habakkuk, Haggai, Nahum, Zechariah, Zephaniah,
Deuteronomy, Amos, Micah, Lamentations, Ezra, Joshua, 2/3 John,
Jude, Philemon, plus "Isaiah"/"Jeremiah"/"Ezekiel"/"Malachi"/"Mat"/
"The Acts"/"Tobit"/"Song of Solomon" spelling variants of books EF
already knows) failed as "unknown book". Added as a new, separate
of_lectionary_table rather than folded into the EF-surveyed table:
none of these 25 new books is attested in the EF's own scans, and
lang/la.ini's own header refuses to fabricate an uncited Latin
title, so they are resolvable (parse + render, falling back to
their own English spelling) but deliberately excluded from Book.all
-- test_lang_coverage.ml's la.ini-completeness promise is preserved
exactly for the ids it already covered, not silently weakened.
2. Parse's grammar could not read a verse number carrying a lectionary
sub-verse letter ("11a", "1bcde") at all -- the dominant remaining
failure shape once (1) was fixed. verse_range now carries a
verse_num { n; suffix } on each boundary, PRESERVED through
rendering rather than dropped (dropping would silently lose real
precision the source text carries). Chapter numbers are untouched
(nothing in the data ever attaches a letter to one).
A third, subtler bug surfaced by (1): registering "jude"/"philemon"/
"2 John"/"3 John" exposed Parse's existing "leading comma-number is a
chapter" heuristic misreading a single-chapter book's bare verse list
("Jude 17,20b-25") as chapter 17 -- a wrong PARSE, worse than the
previous safe "unknown book" failure. Book.is_single_chapter now tells
Parse to skip that heuristic for the four one-chapter books and default
to chapter 1.
Residual, honestly enumerated rather than forced to zero: 41 distinct
references (of 1540) are hyphenated ranges crossing a chapter boundary
("2:29-3:6") -- a Parse.t shape verse_range/part do not represent, a
type restructuring deliberately not attempted this task. Pinned exactly
by the new test_citation_coverage_of.ml, both directions (a new failure
or one of these 41 starting to convert both go red), and disclosed in
data/of/lectionary.sexp's own regenerated provenance header (tools/
bootstrap_lectionary_of.ml now runs the same parser at generation time
and names the count and the set).
Verified EF-unaffected: git diff v1.0.0..HEAD -- lib/kernel/
lib/rites/rite_ef/ data/ef/ is empty, and `colitur day`/`readings`
output for 2027 is byte-identical against the pre-fix binary.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
day_line_of/readings_line_of resolved every displayed name through
lang/la.ini -- data documented as "transcribed from the 1962 Missale
Romanum", i.e. EF vocabulary, keyed on slug. 18 of 222 shipped OF
sanctoral slugs collide with an EF slug there and all 18 printed the
WRONG (1962) title (e.g. "S. Marthae Virg.", a rank word the 1969
reform abolished, silently overriding amendment 011's own "Ss.
Marthae, Mariae et Lazari"); the other 204 had no entry and degraded
to a bare slug, so none of the 208 titles calendar-2002.sexp itself
transcribes (cited against the 2002 Missal) was ever reachable.
Add observed_name_of: prefer the observed celebration's own
Celebration.names (looked up by the requested language code), fall
back to the lang/*.ini table only on a miss. Under --raw this is a
no-op (Lang.raw's own code, "raw", is not a valid 2-letter ISO code,
so the names lookup always misses and falls through to the identity
table exactly as before). EF's day_line/readings_line are untouched --
EF's Celebration.names is almost always empty by design, lang/la.ini
is its real, independently-cited name table.
Regression net, two layers: test_lang_coverage.ml gains a test walking
the real assembled OF layer's entries, asserting that every genuine
lang/la.ini collision resolves to the OF's own name, never the EF
table's; test/cli.t pins one real collision (Martha, 29 July) through
the actual CLI in both la and en.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
data/of/amendments/006-mary-mother-of-the-church.sexp's own header
documented, at length, that Easter+50 can land on 13 June and tie with
Anthony of Padua at Tabula III.10 (both universal Memoria_obligatoria)
-- the ledger's remedy (F-MEMORIAL-TIE) asked to document the lacuna
AND pin the current behaviour so it cannot drift silently. Only the
documentation half was done.
Add test_mater_ecclesiae_anthony_tie_2011_known_arbitrary, in the same
style as the Joseph/Palm Sunday and Holy Family fallback pins already
in this file, but labelled KNOWN ARBITRARY rather than KNOWN WRONG:
no rubric decides this collision (the 2018 decree is silent on it, and
Normae n. 14's third clause resolves only the ad-libitum/ad-libitum
case), so colitur's Slug.compare tie-break is a generic kernel
fallback, not a colitur-invented rule. Asserts the 2011 Easter/offset
arithmetic by hand, the current observed slug, and that the loser is
recorded in `omitted` rather than silently dropped.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
man/colitur.1 documented no --rite flag at all, though the branch adds
it to two commands and ships a whole second rite. Add it to the
day|readings SYNOPSIS line, describe its default/values/refusal
behaviour (matching reject_rite_for's real behaviour) in COMMANDS, and
add the OF data directory to FILES.
While there, LIMITATIONS still said "Only the Extraordinary Form
(1962) is implemented; the Ordinary Form is a planned peer module" --
flatly false now that --rite of is a working, installed feature, and
directly contradicting the flag just documented two sections above it
in the same file. Replaced with an honest statement of the OF's
current validation gap relative to the EF (no published-ordo witness,
known-wrong pinned dates, first reading + Gospel only).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The "KNOWN UNIMPLEMENTED FOURTH RULE" note (Normae n. 56(f)) still said
"No sanctoral data exists yet (Phase 3), so nothing is WRONG today" and
located the trigger at "25 March co-occurring with Palm Sunday". Both
are now false, and the date was already wrong when written: St Joseph
is 19 March, not 25 March -- 25 March is the Annunciation, a separate
solemnity handled elsewhere in this same module.
Phase 3 shipped data/of/calendar-2002.sexp on this branch, so the
defect is now live in 16 of the 1583-2100 years (19 March on Palm
Sunday); rewrite the note to say so and point at where it is pinned
(test_rite_of.ml's known-wrong-forward-transfer test, allow-list
entries L8/L9).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
data/dune's install stanza named only the four EF runtime files, so a
`dune install`ed colitur exited 2 on any --rite of invocation
(`failed to load .../data/of/calendar-2002.sexp`) -- the branch's
headline feature was dead on an installed binary. Add all 15 OF
files (calendar-2002.sexp, the 13 amendments/*.sexp, lectionary.sexp)
to the (files ...) stanza, following the existing ef/ entries' form
and the stanza's own stated rule (deliberately not the litcal
allow-list, a test fixture, same reasoning already given for the EF
pair).
Add a regression guard for the class of bug, not just this instance:
`make check-install` performs a real `dune install --prefix <scratch>`
and runs both rites against the INSTALLED binary, asserting exit 0
and the expected day count. test/cli.t's cram sandbox binds
%{bin:colitur} inside the build tree, where data_dir()/of_data_dir()'s
build-tree fallback candidate resolves even when the installed one is
missing entirely -- so no cram test could have caught this. Wired
into `make check` (unlike check-schema/check-templates/check-citations,
which skip when an optional external tool is absent) since installing
needs nothing beyond what building already needs. Verified the guard
has teeth: reverted data/dune to the pre-fix version and confirmed
check-install fails loudly naming the missing file.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
golden pins
Task 6 (2026-08-25-colitur-of-phases-3-5), the final task of OF Phases 3-5.
Layer 2 (test/test_validate_of.ml, new): Colitur_kernel.Validate.run
against the real, assembled Rite_of.context -- landmark years, the 9999
domain edge, a 200-year QCheck sample, and the full 8417-year exhaustive
sweep under COLITUR_EXHAUSTIVE_SWEEP=1, all filtered through the same
three pinned-not-fixed gaps test_rite_of.ml already names (Normae n.35(a)
Holy Family fallback, the 25-December lectionary gap, St Joseph/Palm
Sunday), duplicated verbatim rather than shared so this file's own
filtering cannot drift from Task 5's silently. Two dedicated 200-sample
properties confirm Ordinary Time weeks are 1..34 with the final week
always 34, and Calendar.year covers its own liturgical year exactly once
with no gaps, both through the resolved pipeline (a genuinely different
code path from Phase 1's own already-exhaustive Temporal_of-level
property). An early version folded a second Calendar.year pass into the
exhaustive loop for these two properties too and measured ~365s for that
alone (a scratch timing harness, not committed); dropped in favour of one
Val.run-only exhaustive loop (~200s), matching the EF harness's shape
(one property, one sweep) rather than tripling it.
test/test_litcal_of.ml extended beyond season/week to GRADE (litcal's own
grade_lcl bucketed against the real Tabula band Precedence_of.band
assigns the day's observed office) and IDENTITY (observed slug against a
hand-verified event_key -> slug table for the closed 46-entity FIXED/
NAMED set -- deliberately not the numbered Sunday/weekday series, a
stated, counted scope limit). Both follow the counted-and-allow-listed
discipline: 1800/4346 rows compared for grade (1763 match, 37 allow-
listed across 5 new entries), 508/4346 for identity (505 match, 3 allow-
listed across 3 new entries), zero unexplained either way. Real
divergences found and adjudicated, not suppressed: litcal's own grade
vocabulary conflates Tabula I.2/I.3 for Trinity/Corpus Christi (verdict
colitur); litcal's Mary Magdalene data predates the 2016 CDW decree
(verdict litcal); a genuine, unadjudicated Sacred-Heart/Nativity-of-John-
the-Baptist tie-break at equal band, found live at the one Easter date in
this fixture's window that creates it (verdict open, no citation found
either way); a second instance of precedence_of.mli's own documented
forward-only transfer_target limitation, on a date shape the mli's own
worked example does not cover (verdict colitur, known limitation).
test/test_golden_of.ml (new, 7 pins): a year Ordinary Time skips a week
(2026) plus Mary Mother of the Church same date; Advent IV on Christmas
Eve in two independent years (2028, 2034); the Annunciation transferred
out of Holy Week to Easter+8 (2027, both ends of the transfer pinned);
All Souls; the Sacred Heart; 17 December's date-keyed reading in two
civil years/weekday-cycle letters.
Every new layer mutation-proved: reverting the Advent-IV fix reddens two
golden pins; corrupting Precedence_of.band's Tabula I.3 value reddens the
litcal grade comparator across every Solemnity in the fixture; renaming
one temporal slug reddens the litcal identity comparator; dropping
Ordinary Time's second season_runs entry reddens both the landmark-years
test and the sampled property. Each mutation applied to lib/rites/rite_of/,
confirmed red, then reverted -- git diff --stat lib/ is empty.
make check (COLITUR_EXHAUSTIVE_SWEEP=1 dune test --force): exit 0, 890
tests, 363.5s. EF byte-identity holds: git diff --stat v1.0.0..HEAD --
lib/rites/rite_ef/ lib/kernel/ data/ef/ is empty.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Temporal_of.named correctly guards the Nativity Vigil: when 24 December
falls on a Sunday it is the Fourth Sunday of Advent (Tabula I.2 outranks
I.3), not the Vigil, and named returns None so temporal's dispatch falls
through to the ordinary Sunday slug. anchors, however, still listed
("of-nativity-vigil", 24 December) unconditionally -- a regression from
the earlier R8 fix, which added the guard to named but never updated
anchors to match. In 2028 and 2034, anchors claimed the Vigil where
temporal actually returns "of-advent-sunday-4".
anchors exists precisely as an independent restatement whose stated
purpose is to catch an accidental single-site drift rather than leaving
it invisible -- it caught exactly this drift, just later than it should
have, only once Validate.run was wired for the OF rite for the first
time (nothing before that compared anchors against named/temporal, so
the two were free to disagree unnoticed).
Fixed by restating named's own guard exactly: the Vigil entry is omitted
on a Sunday year rather than replaced, since the Fourth Sunday of Advent
is an ordinary generic week-numbered Sunday, not one of the named days
anchors exists to restate.
Audited every other anchors entry the same way, across the full
1584-9997 domain (test_temporal_of.ml's own exhaustive sweep, run under
COLITUR_EXHAUSTIVE_SWEEP=1): no further drift found. The sweep does
surface one already-known, already-pinned mismatch -- the "of-holy-family"
entry, in any year 26-31 December holds no Sunday (Normae n.35(a)'s own
30-December fallback) -- but it is a different shape, not a second
instance of this bug: there anchors computes the right date and it is
temporal that fails to reach it, which test_rite_of.ml already found,
pinned and deferred as out of scope. Corrected that file's own stale
comment, which still described the now-fixed Vigil disagreement as an
open gap.
New tests in test_temporal_of.ml cover both a Sunday-24-December year
(2028, 2034) and a non-Sunday one, checking every anchors entry against
temporal directly, plus a positive assertion that the Vigil entry is
correctly present or absent depending on the year.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Christmas-season dates
The bootstrap excluded 19 lectio bases as "date-keyed duplicates", but
17 of them were not duplicates at all: the 8 O-Antiphon days
(17-24 December) and 8 further Christmas-season dates (29-31 December,
2-5 and 7 January) each carry unique per-date content found nowhere else
among the emitted entries, verified against lectio's own ini directly.
17 December is Gen 49:2,8-10 / Matthew 1:1-17, but colitur was falling
through to that year's unrelated weekday-keyed "advent-3-mon" content
instead.
OLM n. 69.3 explains why: those ferias are fixed by civil date, unlike
every other Advent/Christmastide/Paschaltide feria, which is merely
non-alternating within a weekday slot. Temporal_of's own ferial slugs
for these dates are weekday-keyed, so looking one of those up served
whichever OTHER date happened to share that year's weekday alignment --
a citation that silently drifted year to year on ~16 real civil dates
(6 January stays excluded: Temporal_of fixes Epiphany there
unconditionally, so that date can never reach the ferial path at all;
two more, easter-6-thu and advent-4-sat, stay excluded for their own,
different structural reasons).
Fixed with a date-keyed lookup route (Lectionary_of.date_keyed_slug),
tried before the weekday-keyed one in readings' own step 3.
Temporal_of's slugs are unchanged -- only which lectionary key resolves
a day's citations. tools/bootstrap_lectionary_of.ml now maps the 17
bases to synthetic date-keyed slugs instead of excluding them, and its
own reachability sweep calls date_keyed_slug directly so the two can
never drift apart. Re-emitted data/of/lectionary.sexp (754 -> 770
entries) and corrected its provenance header, which previously
described these dates as excluded duplicates.
Also states, for the first time, a Minor finding from the same review:
190 of 222 shipped sanctoral slugs have no dedicated lectionary entry
and correctly fall through to the ferial per OLM norms -- expected
behaviour, not a gap, but never said in the coverage report before.
New tests pin 17 December (Gen 49:2,8-10 / Matthew 1:1-17) and 2 January
(1 John 2:22-28 / John 1:19-28) in two years with different weekday
alignments, proving neither reading drifts, plus direct boundary
coverage of date_keyed_slug itself (both windows, the 6 January
exclusion, and the Sunday guard).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Task 5 of Phases 3-5 (the payoff task): bundles Tasks 1-4's separately
built pieces (Temporal_of, Precedence_of, Rubrics_of, Lectionary_of)
into a (Vocab_of.season, Vocab_of.rank) Colitur_kernel.Rite.t, and
wires colitur day/readings --rite of <year> into the CLI. Default
stays ef; every pre-existing invocation is byte-identical (asserted
directly in test/cli.t and against a real v1.0.0 build for three
years, plus git diff --stat v1.0.0..HEAD over lib/rites/rite_ef/,
lib/kernel/, data/ef/ is empty).
No kernel change was needed, confirming the spec's central claim.
season_runs needed real thought rather than the brief's own suggested
Vocab_of.seasons: Temporal_of.season's own 'first run'/'second run'
comments confirm Ordinary Time is genuinely interrupted by Lent and
Easter over one liturgical year, so the expected run-length-compressed
sequence names it twice, six runs over five seasons -- exactly the
case Rite.t.season_runs's own doc comment already names as its
illustration for why this field is rite-supplied rather than derived.
easter/fixed_key are as specified, each carrying its own citation
(Gregorian computus; the 2002 Missal's one bissextilis occurrence is a
leap-year table entry, not a kalends-doubling rule, so fixed_key is
identity).
Follows rite_ef.ml's template and its lectionary-parameter lesson
exactly: lectionary is caller-supplied, not closed over.
test/test_rite_of.ml resolves the real assembled rite (calendar-2002
.sexp + all 13 amendment overlays + lectionary.sexp) through Calendar
and Validate.run, the same discipline test_validate.ml/test_rite_ef.ml
already apply to EF. This is the first time rite_of has been checked
this way, and it surfaced two new, real, cited gaps outside this
task's own scope to fix: Temporal_of never reaches Normae n.35(a)'s
30-December Holy Family fallback in a year with no Sunday in 26-31
December (first hit 1583, the domain floor), and Temporal_of.anchors
disagrees with temporal on 24 December when that date is itself a
Sunday (Advent IV outranks the Vigil, first hit 2006). Both pinned as
known-wrong, not fixed, the same treatment the brief's own pre-known
St Joseph/Palm Sunday gap (Normae n.56(f)) gets, pinned on 2062. A
third gap was found in data/of/lectionary.sexp's own coverage (audited
against one civil year only, so the other weekday-cycle letter is
unaudited and at least one pairing is asymmetric on shipped data) --
that file is excluded from this task, so the wide 2005-2050 sweep
checks structural invariants only and leaves the citation-chain checks
to the small, individually-audited landmark-year set.
make check (COLITUR_EXHAUSTIVE_SWEEP=1): exit 0, 867 tests, ~316s.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Task 4 of Phases 3-5: the last Rite.t field OF still needed, `readings`.
The cycle rules are CODE, cited to OLM (Ordo Lectionum Missae) 1981
Praenotanda -- verified against the real page image
(docs/research/of/olm-1981.pdf pp.32-33/"XXXII-XXXIII"), not the
document's own unreliable OCR text layer, per the design spec's own
caveat. n. 66 (with its footnote 102's worked example, 1980=C/1981=A/
1982=B/1983=C) gives the three-year Sunday cycle; n. 69 point 4 gives
the two-year weekday cycle, Year I in odd label years, Year II in
even. Both derive the "label year" the same way: one more than the
civil year Advent I opened in, per n. 66's footnote 102 itself
("nempe a prima hebdomada Adventus, quae cadit in anno civili
praecedente") -- so the cycle turns at Advent I, not 1 January, exactly
where the task brief said to get it right. The design spec's own
citation for the weekday rule, "Praenotanda n. 649", does not survive
a direct check against the primary source (search finds "649" only in
unrelated index/page-number entries); corrected here to n. 69, the
paragraph the rule's own Latin text actually sits under, confirmed by
the page image's own printed margin number.
The data is bootstrapped from lectio's of-lectionary.ini (988 keys,
niedziela.pl, harvest 2020-2025) by tools/bootstrap_lectionary_of.ml
-- OCaml, not the brief's own suggested .py: tools/bootstrap_lectionary
.ml already established this exact shape for EF, including a real
safety net ([assert_reachable], sweeping Rite_of.Temporal_of.temporal
AND the real merged sanctoral layer directly) that a second-language
reimplementation would either duplicate or lose. Handles two real
data anomalies found while building it: one malformed ini line (a
Polish Septuagint-numbering annotation for Sirach 3, "Syr 3,2-6.12-14"
against OLM/CEI/USA's shared Nova Vulgata, matching the design spec's
own sec5 finding); and two Sunday-cycle-labelled bases (Annunciation,
Immaculate Conception) where a scraping-year artifact left one of
three cycle letters carrying a different day's Mass entirely --
resolved by a general, mechanical 2-of-3 majority rule, not a
per-saint hand edit, and logged.
Coverage measured in both directions, per the brief's own Step 1:
- 1 of 365 days in civil year 2026 (25 December, the Christmas DAY
Mass) has no Temporal_of-slug match anywhere in lectio's 988 keys --
only the Vigil is present. Named in the data file's own header.
- 0 of 438 distinct lectio bases map to no colitur slug, after 19 are
deliberately excluded (late-Advent/Christmas-season DATE-keyed
duplicates lectio also carries in a WEEKDAY-keyed form colitur's own
slugs actually match -- Lectionary.t has no date-keyed lookup at
all, so the date-keyed family is transcription-inert, not silently
dropped: named explicitly, not a residual).
Lectionary_of.readings is three steps (no Commons indirection, unlike
EF -- out of this task's scope): the observed celebration's own
embedded citations; else, for a real sanctoral winner, its own slug
looked up directly (flat, then both cycle letters); else the day's
own temporal slug, same lookup. No preceding-Sunday fallback: OF's own
two-year cycle assigns every Ordinary Time weekday its own reading by
design, and no OF norm was found instructing otherwise.
Tests (test/test_lectionary_of.ml, 12 cases): a cycle-arithmetic table
straddling Advent 1980/1981/1982/2025 inside single civil years,
reproducing OLM n.66's own worked example directly; SHA-256 pins on
both the emitted file and lectio's own source (embedded in the
provenance header); a pinned, NAMED 2026 coverage result (364 resolve,
exactly {25 December} does not -- never a bare count); two resolution-
chain spot checks (a plain ferial, and a saint's day beating the
ferial it would otherwise fall on); and a real subprocess test that a
missing lectio source file fails the generator loudly, non-zero exit,
no output written -- the exact bug Task 1's own generator shipped and
needed a review round to fix.
dune test: exit 0, 856 tests. make check (COLITUR_EXHAUSTIVE_SWEEP=1,
full 1583-9999 sweep): exit 0, 862 tests, ~342s, both run unpiped in
the foreground. git diff --stat v1.0.0..HEAD -- lib/rites/rite_ef/
lib/kernel/ data/ef/ still empty.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fix round 1 for Task 3, addressing review findings.
Rename the exported creed function from `credo` to `creed` across the
.ml, .mli and test call sites, so the OF rite bundle can write
`creed = Rubrics_of.creed` with no gratuitous mismatch against
Rite.t's own field name, matching Rite_ef.Rubrics_ef.creed's own
naming. IGMR n. 67's own heading is "Professio fidei" and its body
says "Symbolum", never "Credo" -- documented as a comment on the
now-correctly-named function rather than kept as the exported name.
Local test helpers (credo_on_temporal, check_credo, test_credo_*) and
Alcotest description strings keep the Latin shorthand, since only the
call sites against RO.creed needed to change.
Corrected two comment inaccuracies:
- The Annunciation (25 March) is NOT always inside Lent, unlike St
Joseph (19 March): 25 March sits after Easter's own earliest
possible date (22 March), so in an early-Easter year (2008, Easter
23 March) it falls inside the Easter Octave instead, or is
transferred under Normae n. 60/5. No functional effect (gloria/creed
read observed/temporal as actually resolved), but the stated reason
was wrong.
- The Requiem-silence argument's counts: three All Souls Mass
formularies (not two), and roughly 147 Gloria+Credo markers combined
elsewhere in the Missal (not "over 150", which conflated Gloria
alone with the combined figure) -- recounted directly against a
fresh pdftotext -layout extraction rather than estimated.
Added: an independent corroborating citation for the Holy Thursday /
Easter Vigil Gloria exception, Vigil n. 31 -- the Easter Vigil's own
praenotanda ("VIGILIA PASCHALIS IN NOCTE SANCTA"), a THIRD
independently-numbered rubric set inside the same Missal PDF,
confirming the Vigil's own Gloria directly rather than resting solely
on the Holy Thursday rubric's forward-looking "usque ad" clause.
dune test: exit 0, 845 tests. make check (COLITUR_EXHAUSTIVE_SWEEP=1,
full 1583-9999 sweep): exit 0, 851 tests, 330.3s, both run unpiped in
the foreground. git diff --stat v1.0.0..HEAD -- lib/rites/rite_ef/
lib/kernel/ data/ef/ still empty.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Task 3 of OF Phases 3-5: the celebrant-rubrics module for the OF rite,
supplying three of Rite.t's four remaining fields.
creed/gloria implement IGMR n. 53 (Gloria) and n. 67-68 (Symbolum),
both quoted in full in the module header. temporal is read, not
observed, for both Sunday clauses: Temporal_of.temporal tags every
Sunday of Advent/Lent/Easter Sollemnitas (the privileged-season
convention), so an observed.rank test alone would wrongly grant Gloria
on an Advent or Lent Sunday, which n. 53's own "extra tempus Adventus
et Quadragesimae" explicitly withholds. Credo is deliberately narrower
than Gloria: n. 68 has no "et festis" clause, so an ordinary Festum
does not get the Creed, unlike EF's RG 475(b)/(c). Two Missale-proper
exceptions (Holy Thursday evening Mass, the Easter Vigil Mass) are
cited from the Missal's own "Dicitur Gloria in excelsis" rubric, not
the IGMR, which is silent on both. The Requiem question is likewise
IGMR-silent (nn. 379-385 say nothing about Gloria/Credo); flagged as
an inference from the Missal's own consistent marker pattern, applied
only to the one Requiem-shaped slug the shipped OF data can construct
(all-souls), the same closed-population discipline Rubrics_ef's own
Colour.Black proxy uses.
preface returns None unconditionally, a measured verdict rather than
a stub. The module header transcribes the 2002 Missal's own "INDEX
PRAEFATIONUM" in full: nine of Preface.t's 15 EF-cited constructors
name an OF occasion with multiple distinct texts (Nativity x3, Lent
x4-9, Easter x5, Ascension x2, Holy_spirit x2, Bvm x5, Apostles x2,
Common split across two independent 7/8-member families, Requiem x5)
-- structurally lossy to collapse into one constructor. The other six
(Epiphany, Trinity, Sacred_heart, Christ_the_king, St_joseph,
Holy_cross) match cardinality with a single OF text apiece, and were
checked and rejected anyway: Preface.t's own constructors are RG-cited
by construction, and IGMR n. 364's own "quibus Missale Romanum
ditatur" (prefaces the Missal is ENRICHED with) is direct textual
evidence the 2002 collection is not a bare carry-over -- corroborated
directly for Sacred Heart, whose OF text was read and found to be a
different composition from its RG 491 namesake. Reusing any of the
six on cardinality and theme alone would be the exact "sounds similar"
trap the task brief warns against.
test/test_rubrics_of.ml: 26 table-driven cases. Every temporal-origin
row builds observed via Temporal_of.temporal on a real date; every
sanctoral-origin row (a solemnity in Lent, an ordinary Festum, a
weekday obligatory memorial, All Souls) pairs a real Temporal_of.temporal
result with an observed record copied verbatim from
data/of/calendar-2002.sexp, since no full OF Rite.t/Calendar pipeline
exists yet to derive one. Includes same-date Gloria/Credo pairs that
prove the two rules genuinely diverge (a Sunday of Advent, an ordinary
Festum) rather than one silently mirroring the other.
dune test: exit 0, 845 tests. make check (COLITUR_EXHAUSTIVE_SWEEP=1,
full 1583-9999 sweep): exit 0, 851 tests, 303.6s, both run unpiped in
the foreground. git diff --stat v1.0.0..HEAD -- lib/rites/rite_ef/
lib/kernel/ data/ef/ is empty.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds data/of/amendments/*.sexp: 13 overlay files, one per decree,
carrying the General Roman Calendar's amendments since the 2002 typical
edition (docs/research/of/PROVENANCE-amendments.md's own 15-item
inventory, items 10-12 sharing one decree; items 2 and 3, though issued
the same day, carry different protocol numbers and are counted as two
decrees). 14 Add directives (Padre Pio, Juan Diego, Guadalupe, John
XXIII, John Paul II, Mary Mother of the Church, Paul VI, Loreto,
Faustina Kowalska, Gregory of Narek, John of Avila, Hildegard of Bingen,
Teresa of Calcutta, John Henry Newman) and 2 Edit directives (Mary
Magdalene's rank memoria->festum; Martha/Mary/Lazarus's name widened,
same slug, same date and rank -- a continuation of the existing
memorial per the decree's own text, not a suppression and replacement).
Mary, Mother of the Church is the one movable entry (Easter_offset 50,
the Monday after Pentecost) -- verified against the decree's own text
and against Colitur_kernel.Computus.gregorian_easter in three real
years, no kernel change needed.
data/of/calendar-2002.sexp is untouched, per spec sec4.1.
Adds test/test_amendments_of.ml: every file parses, each has a pinned
SHA-256, applying all 13 in decree order yields 222 entries (208 base +
14 Add) with an empty Overlay.merge diagnostics list, and Mary Mother of
the Church resolves to the Monday after Pentecost in three real years.
Two Precedence_of interactions are recorded, not fixed (out of scope for
a data-only task): a movable Memoria_obligatoria can land on an existing
fixed one (verified for 13 June 2011), a genuine band tie Normae n. 14
does not address and Precedence_of.ml does not implement; and adding
Hildegard of Bingen changes which of two ad-libitum memorials on 17
September Precedence.resolve reports as observed, by alphabetical
tie-break alone.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Four fixes from fix round 2 review:
classify_subject's "maria"/"b.m.v" substring test over-matched 12 saints
who merely carry "Maria" in their own name (Maximilian Mary Kolbe, John
Mary Vianney, Mary Magdalene among them) as Bvm. Replaced with an
explicit BVM_DATES table of the 13 genuinely Marian entries. Bvm 25 -> 13.
The provenance header claimed lectio is "never a source", which omitted
that slugs and English names both come from it. Corrected to state
exactly what does (slugs, en names) and does not (every substantive
field) come from lectio. A missing lectio file used to degrade silently
to a different SHA-256 with no en names and no warning; it now fails
loudly. lectio's own SHA-256 is now pinned alongside the Missal PDF's.
Four more entries carried a second pdftotext artifact distinct from the
letter-spacing already handled -- a combining diacritic rendered as a
stray spacing character (Kim Taegŏn/Chŏng Ha-sang, Đũng Lạc, Makhlūf,
Kęty). Hand-repaired the same way Peter Damian was, each corroborated by
the identical corruption recurring in the Missal's own index.
precedence_of.ml's PHASE 3 HAZARD comment about All Souls (2 November)
was asserting a gap that no longer exists now that OF sanctoral data
ships. Added test_all_souls_beats_an_ordinary_sunday, which resolves the
shipped All Souls entry against a real per-annum Sunday (2025-11-02)
through the actual Precedence.resolve pipeline, and updated the comment
to record the resolution instead of demanding it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Both are printed in the 2002 calendar table, immediately after 30 June, as
prose headings rather than (kalends, day) rows -- the shape parse_rows'
generic movable-heading skip branch was built for, which is why the first
pass silently dropped them. They belong in the transcription, not in
Temporal_of: adding them completes the table this file transcribes rather
than amending the temporal cycle.
Produced as Date_spec.Easter_offset entries (68 and 69 respectively), the
same variant already used for EF's Rogation Wednesday and needing no
kernel change. Pentecost is Easter+49, so the Friday and Saturday after
the Second Sunday after Pentecost are Easter+68/+69 -- verified against
three real Easter dates (2026, 2027, 2035), not merely computed on paper.
The extractor now recognises these two headings specifically among the
seven "Dominica/Feria/Sabbato ... :" headings the table contains; a full
audit of the other five confirms each is already covered by Temporal_of
and correctly stays excluded here. 206 -> 208 entries.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Extracted from the Latin typical edition, which is the authority; lectio's
roman-calendar.ini is a cross-check only and every divergence is adjudicated
against the Missal in the provenance header.
A blank grade column means Memoria ad libitum, per the calendar's own
footnote, rather than a missing value. 206 entries; 1 January, 6 January and
25 December are deliberately excluded because Temporal_of.named already
computes them, and shipping them here too would create a duplicate
candidate for the same day.
Colour is derived from IGMR n. 346, cited per class in the extractor; the
lectio cross-check surfaces one rank divergence (22 July, Mary Magdalene --
lectio reflects the 2016 post-2002 elevation decree, out of scope here) and
17 colour divergences, all adjudicated in the provenance header.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Temporal_of.named claimed 24 December unconditionally as
of-nativity-vigil (Sollemnitas), and temporal's dispatch matched named
before sunday_slug. On a Sunday 24 December, the Fourth Sunday of
Advent -- Tabula I.2, Normae n. 5's own privileged Sundays of Advent,
Lent and Easter -- was silently replaced by the Vigil.
named now returns None for 24 December when that date is itself a
Sunday, so temporal's dispatch falls through to sunday_slug and the
day resolves as of-advent-sunday-4. The Vigil Mass is an evening Mass
of the following solemnity, not an office belonging to 24 December's
own civil day -- the same civil-day-granularity reasoning already
applied to Holy Thursday (Precedence_of.band's entry-1 comment) and to
expected-divergences-litcal.sexp's L1 entry. Every non-Sunday
24 December is unaffected.
Audited every other named entry for the same latent shape (see
.superpowers/sdd/of-r8-advent-iv-report.md): none of them has it,
either because the date can never fall on a Sunday, or because the
date IS the definition of that Sunday (Palm Sunday, Easter, Pentecost,
Trinity, Christ the King), or because the competing movable-Sunday
windows are constructed to exclude that date.
Added test_nativity_vigil_yields_to_advent_sunday, covering
2028-12-24 and 2034-12-24 (both inside the litcal fixture window) and
the 2026-12-24 non-Sunday control. Re-ran the litcal layer: no
allow-list counts moved, since it compares only season and
Ordinary-Time week, and both readings of 24 December are "advent"
either way. Updated test_precedence_of.ml's "entry 3, not 9" comment,
which had carried this as a known, unfixed defect, to describe the
fix; its own pinned assertion (a hand-built Thursday candidate) needed
no change.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fix wave from the final whole-branch review of OF Phase 2 (0 Critical,
5 Important, 8 Minor). Applies the five items ruled in-scope and records
two more, per the controller's R7/R8/R9 rulings.
Fixes:
- temporal_of.ml: season-boundary header cited "Normae n. 71-77", a range
that does not exist (the Normae end at n. 61) and collides with real IGMR
nn. 71-77 (Preparation of the Gifts) in the same PDF -- EF leakage from
RG 71-77. Corrected to Normae Titulus II, nn. 17-47, with a note against
reintroducing the wrong range.
- precedence_of.ml entry 3: added the Tabula's second clause (Commemoratio
omnium fidelium defunctorum / All Souls) to the comment, and recorded the
Phase 3 hazard -- Vocab_of.rank has no constructor for it yet, and every
natural tagging choice gets 2 November's precedence wrong in a different
way. No code change; nothing can construct the entity yet.
- precedence_of.ml transfer_target's search: added a domain_max_date guard
(following Rite_ef.Precedence_ef's existing shape and reasoning) so the
walk can no longer probe Computus past 9999-12-31, and it now returns the
last date visited on bound exhaustion instead of failwith-ing. .mli
updated to drop the @raise Failure clause.
- precedence_of.ml is_privileged_sunday: added its own inline Tabula I.2
citation, matching its sibling helpers.
- precedence_of.ml entry 10: trimmed the reused "universal or temporal-origin"
comment -- Temporal_of never constructs a Memoria_obligatoria candidate, so
the temporal-origin half was vacuous there.
Recorded without fixing (both comment-only, per explicit scope ruling):
- test_precedence_of.ml: corrected the entry-3 Nativity Vigil test's
characterisation. The pinned band-30 assertion (2026-12-24, a Thursday) is
correct, but is not the value on a 24-December Sunday (e.g. 2028, 2034),
where is_privileged_sunday instead bands the same candidate 20. Named the
underlying Phase 1 defect this exposes -- named() claims 24 December
unconditionally and is matched before sunday_slug, so the Fourth Sunday of
Advent gets no office at all in those years, invisible to the litcal layer
-- as known and carried to the next task.
- precedence_of.mli transfer_target: documented Normae n. 56(f) (St Joseph
on Palm Sunday anticipates backward to 18 March) as a known, cited,
unimplemented fourth transfer rule, and named the underlying kernel
constraint (Rite.t.transfer_target's strictly-later obligation, justified
only by the EF's RG 96) as the reason a real fix needs a kernel change.
dune test: 799 tests, exit 0. make check (exhaustive sweep): 805 tests,
exit 0, 224.7s. No kernel/rite_ef/data changes (git diff empty).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three rules, in priority order: the Annunciation in Holy Week goes to
Easter+8; any other solemnity on a Sunday of Advent, Lent or Easter goes to
the following Monday (n. 5, which n. 60 defers to explicitly), except on Palm
Sunday or Easter Sunday; otherwise the nearest later day free of Tabula
entries 1-8.
The n. 5 Monday rule is easy to miss -- n. 60 names it only by cross
reference, and reading n. 60 alone yields a single search rule where the
sources give three.
Shaped to match Rite.t.transfer_target so a later phase wires it unchanged,
with its own step bound: Calendar's round guard bounds rounds, not one call's
internal search.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The prior comment claimed of-nativity-vigil is 'not a distinct celebration' -
wrong: Temporal_of.named (temporal_of.ml:230) constructs it as its own
Sollemnitas-rank candidate on 24 December, a genuine contestant in
band/Precedence.resolve.
The real reason None is safe is structural, not that. The Nativity is
Tabula entry 2 (band 20); only entry 1, the Paschal Triduum (band 10),
bands lower. The Triduum's Easter-2..Easter window is confined to 20
March-25 April because Gregorian Easter never falls outside [22 March, 25
April] over the whole 1583-9999 domain (measured exhaustively in
test_computus.ml, not assumed), so it can never reach 25 December. The
Nativity therefore always keeps its own day and its vigil can never be
orphaned by a transfer or reduction.
Behaviour is unchanged: vigil_feast still returns None unconditionally.
RG 33 (EF-only) and Normae nn. 11/13 remain the reason the hook exists at
all and returns None for every other candidate.
|
| |
|
|
|
|
|
|
|
|
| |
admit returns the empty list because disposition never returns Commemorate;
vigil_feast returns None because the OF has no vigil office that its feast's
movement could orphan -- 'of-nativity-vigil' is a Mass formulary of the
solemnity, not a separate celebration.
Both are argued from the sources rather than stubbed, and Precedence_of.rules
now assembles the four functions the kernel resolver consumes.
|
| |
|
|
|
|
|
|
|
|
| |
An impeded solemnity transfers; every other loser is omitted for that year
('Reliquae celebrationes eo anno omittuntur').
Commemorate is never returned, and that is the rule rather than a gap: the OF
has no commemoration of a losing celebration in the EF's sense, and an
optional memorial is an election rather than a commemoration. A property over
every rank pairing asserts it, so a later edit cannot quietly introduce one.
|
| |
|
|
|
|
|
|
|
|
| |
A hand-transcribed 13-entry table is only trustworthy if nothing the engine
constructs falls through it. Sampled property plus an exhaustive sweep behind
COLITUR_EXHAUSTIVE_SWEEP, matching the claim Precedence_ef.band already
carries for RG 91's 28 entries.
Mutation-proved rather than assumed: deleting the entry-13 branch reddens it
on a named date.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Entries 10-13. Entry 12 is one undivided row -- the Tabula draws no
universal/proper split for optional memorials, unlike entries 3/4, 7/8 and
10/11 -- so it deliberately does not read the layer.
Entry 13's four clauses need no date arithmetic of their own: every
privileged feria is entries 2 and 9, tested earlier in the chain, so what
reaches the final branch is exactly the residue those clauses name.
Entry 10 uses [not (is_proper layer)], not the brief's original
[is_universal layer]: is_universal was deleted as dead code in Task 2,
because every temporal-origin candidate carries layer = "temporal", never
universal_layer, so a positive is_universal test can never match one --
the same correction entries 3, 5 and 7 already apply.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fix round 1 (coordinator review). The Nativity Vigil (24 December,
Sollemnitas) bands at entry 3 (30) rather than entry 9 (90) as a direct
consequence of this task's ruling, but nothing pinned it -- a future
branch-reorder (e.g. inserting an entry between 3 and 9, or loosening
entry 9's date guard) could silently revert it to 90 with the suite
green.
Adds one row to part2_cases with a comment recording: the Tabula's own
entry 9 textually covers 24 December as a late-Advent feria, yet Phase
1 gives that civil day the of-nativity-vigil identity at Sollemnitas
because the Vigil Mass is celebrated that evening -- the same
civil-day-granularity shape Holy Thursday already settles (entry 2,
not entry 1); Phase 2 classifies Phase 1's emitted identity rather
than overriding it. Unobservable on the universal calendar today (no
competing candidate on 24 December); live under a proper/diocesan
overlay, where a proper solemnity (entry 4, band 40) loses to the
Vigil at 30 but would beat it at the textually-arguable 90.
No production code change -- test-only, per the coordinator's ruling
to pin current behaviour rather than alter it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Entries 5-9. Entries 5 and 7 differ only by subject -- 'Festa Domini'
against 'Festa beatae Mariae Virginis et Sanctorum' -- so they key on
Celebration.t.subject, the same field RG 91 entry 14 uses on the EF
side, never on the slug.
Entry 9's three clauses (late-Advent ferias from 17 December, the
Nativity octave, Lenten ferias) are what separates a privileged feria
from the ordinary one at entry 13.
CORRECTION to the task brief, applied here rather than after: entries
3, 5 and 7 test 'not (is_proper layer)', not 'is_universal layer'.
Every temporal-origin candidate Temporal_of.temporal constructs
carries layer = "temporal" unconditionally, never universal_layer, so
a positive universal-layer test silently excluded every temporal-cycle
solemnity and Lord-subject feast from these entries -- Corpus Christi
came out unclassified outright, and Trinity/Christ the King/Holy
Family/the Baptism of the Lord landed one entry too low. is_universal
is now dead and removed; entry 3's branch (written in Task 1) is
amended along with the new entries 5 and 7. Only entries 4 and 8 still
test is_proper directly, matching the Tabula's own proper-calendar
rows.
Also fixes a pre-existing typo in the brief's own 'entry 6: a Sunday
per annum' test row: rank was Sollemnitas, which -- being tested at
entry 3, earlier in the chain -- made the row fail regardless of the
is_universal/is_proper question, since no real Sunday per annum is
ever Sollemnitas. Changed to Festum, matching the adjacent 'Sunday of
Christmas time' row and real Temporal_of output.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The Tabula dierum liturgicorum's entries 1-4, one band branch each, scaled
x10 as Precedence_ef's own table is. The Triduum is identified structurally
by Easter offset because Temporal_of emits Good Friday and Holy Saturday as
ordinary Lent week-6 ferias, leaving no slug to key on.
Holy Thursday sits at entry 2, not entry 1: the Tabula's own entry 2 runs
'a feria II ad feriam V inclusive' and the Triduum opens with an evening
Mass inside that civil day. Same granularity decision the litcal layer's L1
records on the season axis.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds a sixth-lineage external validation layer for the OF rite module's
Phase 1 temporal cycle, targeting the single highest-risk function that
report named: the two-block Ordinary Time week arithmetic (Normae n. 44),
which has no external witness anywhere in Phase 1's own suite and whose
output selects the Mass formulary, not merely a label.
Witness: litcal (Liturgical Calendar API), Apache-2.0, already archived
and SHA-256-pinned by the sibling lectio project. AELF was considered and
correctly excluded earlier (its CGU forbids redistribution) -- litcal is
what it was replaced with.
- tools/extract_litcal_ordo.py verifies all twelve archived
calendar-YYYY-en.json files (2024-2035; the task brief said eleven,
but twelve are actually pinned in lectio's manifest -- all twelve are
used) against lectio's own manifest.tsv, then builds one fixture
spanning the contiguous 4382-day range those twelve liturgical-year
files cover.
- test/fixtures/litcal-temporal-2024-2035.sexp: one row per day, season
and (where witnessed) Ordinary Time week, with full provenance,
licence, per-year Easter dates and the row-selection rules in its own
header.
- test/test_litcal_of.ml calls Temporal_of.temporal directly (no Rite.t)
and compares 1:1 against the fixture: zero Ordinary Time week
mismatches on all 1876 witnessed days (zero tolerance, no allow-list);
the only season divergence class is the Sacred Triduum, which litcal
tags with a season value colitur's vocabulary deliberately has none of
-- one cited allow-list entry, data/of/expected-divergences-litcal.sexp,
36 rows, exact.
- Mutation-tested: dropping the backward-from-34 adjustment reddens this
layer (1511 of 1876 days) plus three pre-existing Phase 1 tests; the
mutation was not committed.
Does not touch lib/rites/rite_ef/, data/ef/, or lib/rites/rite_of/ --
this validates Phase 1, it does not change it. Full suite: 786 tests via
dune test, 791 via make check, exit 0 both; lib/bin diff empty throughout.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The first code for a second rite. lib/rites/rite_of/vocab_of implements
the OF's five-way rank vocabulary (Sollemnitas/Festum/Memoria_obligatoria/
Memoria_ad_libitum/Feria) and five-season vocabulary (Advent/Christmas/
Lent/Easter/Ordinary_time), each constructor cited against the 2002
Missale Romanum's Normae universales and the Tabula dierum liturgicorum.
temporal_of implements season boundaries, week numbering — including
Ordinary Time's own two-block resumption, derived from the Missale's own
"HEBDOMADA I/XXXIV 'per annum'" headings and empirically verified across
the whole 1583-9999 domain — named temporal days, and Sunday/ferial
slugs. Both satisfy Colitur_kernel.Temporal.RITE with no kernel change.
No Rite.t is assembled and no CLI wiring is added (Phase 2's own scope);
lib/rites/rite_ef and data/ef are untouched, verified byte-identical
against the v1.0.0 tag across a domain-spanning sample.
test/test_temporal_of.ml adds unit tests for every boundary and named day
plus seven QCheck properties (seasons contiguous, Ordinary Time weeks in
1..34, Advent always four Sundays, slug uniqueness, weekday agreement,
determinism, consecutive liturgical years partition civil time), with a
committed exhaustive sweep mirroring test_validate.ml's own convention.
Full account, including the Ordinary Time derivation's evidence and a
list of EF concepts that do not carry over, in
.superpowers/sdd/of-phase1-report.md (untracked, gitignored).
|
| | |
|
| | |
|
| |\
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
colitur now prints what a real ordo prints for the Mass: which formulary is
said and how it was reached, the Gloria, the Creed, the preface, and the
commemorations with their Low-Mass/sung distinction. colitur rubrics joins
day and readings.
Four defects were found and fixed on the way, each by an external witness
rather than by inspection: the Creed said at Requiem Masses (RG 476(f)),
the missing bissextile shift of St Matthias and St Gabriel (2 041 leap
years), Rogation Monday and Tuesday coloured violet in Paschaltide (RG
119(b)), and the ferias after the Ascension resuming the wrong Sunday's
Mass rather than the Ascension's.
Validation gained a sixth layer and then some: the preface is checked
against three independent publishers over seven witness-years (FIUV, three
LMS editions, three extraordinaryform.org editions), none of which shares
the Divinum Officium -> missalemeum -> lectio lineage the older layers all
descend from.
|