1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
Easter and its Easter-relative movable feasts for a year:
$ colitur easter 2026
easter 2026-04-05
ash-wednesday 2026-02-18
palm-sunday 2026-03-29
ascension 2026-05-14
pentecost 2026-05-24
corpus-christi 2026-06-04
A year outside the supported domain is rejected (exit 2):
$ colitur easter 1000
colitur: year 1000 out of range 1583..9999
[2]
No/garbage arguments give a usage error (exit 2):
$ colitur
colitur: usage: colitur easter <year> | colitur temporal <year> | colitur day <year> | colitur readings <year>
[2]
The EF temporal cycle for a year, one line per day:
$ colitur temporal 2026 | head -3
2026-01-01 thursday christmastide - ef-circumcision class-1 white
2026-01-02 friday christmastide - ef-christmas-1-friday class-4 white
2026-01-03 saturday christmastide - ef-christmas-1-saturday class-4 white
$ colitur temporal 2026 | wc -l
365
$ colitur temporal 2026 | grep -c '^2026-04-05 '
1
$ colitur temporal 2026 | grep '^2026-04-05 '
2026-04-05 sunday paschaltide 1 ef-easter-sunday class-1 white
A year outside the supported domain is rejected (exit 2):
$ colitur temporal 1000
colitur: year 1000 out of range 1583..9999
[2]
The resolved EF calendar for a year (Task 11) -- temporal AND sanctoral,
occurrence and transfers applied: one line per civil-year day,
"YYYY-MM-DD weekday season week slug rank colour [+commemoration-slug]...".
$ colitur day 2026 | wc -l
365
Easter is the observed day exactly once, and carries no commemoration (an
impeded I class day admits at most one PRIVILEGED commemoration, RG 111, and
nothing outranks Easter to be impeded by it in the first place):
$ colitur day 2026 | grep -c '^2026-04-05 '
1
$ colitur day 2026 | grep '^2026-04-05 '
2026-04-05 sunday paschaltide 1 ef-easter-sunday class-1 white
Ash Wednesday: I class (RG 91 entry 7), violet, no numbered week (it falls 4
days before Lent I's own origin -- rite_ef/temporal_ef.ml's [week]):
$ colitur day 2026 | grep '^2026-02-18 '
2026-02-18 wednesday lent - ef-ash-wednesday class-1 violet
Christmas: I class, white (RG 91 entry 1):
$ colitur day 2026 | grep '^2026-12-25 '
2026-12-25 friday christmastide - ef-nativity class-1 white
All Souls (2 Nov, RG 91 entry 8) end to end: 2 Nov 2025 is a Sunday (verified
independently -- 1 Jan 2025 is a Wednesday, day-of-year 306, (3+305) mod 7 =
0 = Sunday), so entry 8 yields to it (still an ordinary II-class Sunday,
"sunday" in season time-after-pentecost, colour green -- the week number
itself is not re-asserted here, already covered by test_temporal_ef.ml); RG
95 then transfers All Souls (I class, not a Sunday, not a vigil) and RG 96
places it on 3 Nov, the next day that is not I or II class:
$ colitur day 2025 | grep -c 'commemoration-of-all-souls'
1
$ colitur day 2025 | grep '^2025-11-02 ' | sed -E 's/ [0-9]+ ef-time-after-pentecost-sunday-[0-9]+ / <week> ef-time-after-pentecost-sunday-<n> /'
2025-11-02 sunday time-after-pentecost <week> ef-time-after-pentecost-sunday-<n> class-2 green
$ colitur day 2025 | grep '^2025-11-03 '
2025-11-03 monday time-after-pentecost 21 commemoration-of-all-souls class-1 black
(week 21: Pentecost 2025 is 8 June (colitur easter 2025); 8 Jun - 3 Nov is
148 days, floor_div(148, 7) = 21 -- rite_ef/temporal_ef.ml's own [week]
formula, hand-verified before promoting this line, not merely printed and
trusted.)
All Souls observed directly on 2 Nov in a year where it does not fall on a
Sunday: 2 Nov 2026 is a Monday (1 Jan 2026 is a Thursday, same day-of-year
306 offset, (4+305) mod 7 = 1 = Monday):
$ colitur day 2026 | grep -c 'commemoration-of-all-souls'
1
$ colitur day 2026 | grep '^2026-11-02 '
2026-11-02 monday time-after-pentecost 23 commemoration-of-all-souls class-1 black
(week 23: Pentecost 2026 is 24 May (colitur easter 2026); 24 May - 2 Nov is
162 days, floor_div(162, 7) = 23 -- same formula, same independent check.)
RG 96's Annunciation exception (25 March) is CONDITIONAL, not unconditional
-- fix round 1, coordinator review, register corrected 2026-08-12. In 2057,
25 March is Lent III Sunday (I class, impedes it); 26 March is an ordinary
Lent feria (III class, well before Easter, 22 April 2057), so the GENERAL
RG 96 target -- not the Monday after Low Sunday -- is what governs, since
the general walk never crosses Easter. Before this fix the unconditional
reading sent it to 30 April (Easter + 8) instead:
$ colitur day 2057 | grep '^2057-03-26 '
2057-03-26 monday lent 3 annunciation-of-the-blessed-virgin-mary class-1 white +ef-lent-3-monday
$ colitur day 2057 | grep -c 'annunciation-of-the-blessed-virgin-mary'
1
A year outside the supported domain is rejected (exit 2):
$ colitur day 1000
colitur: year 1000 out of range 1583..9999
[2]
The reading citations for a year, one line per day: date, the observed day's
slug, then the Epistle and the Gospel, " | "-delimited.
A SEPARATE command rather than extra columns on `colitur day`, for a
mechanical reason: a citation contains spaces and commas ("Ezech 34:11-16",
"Ecclus 51:1-8, 12"), while a `day` row is space-separated with a
variable-length "+slug" commemoration tail, so appending them there would
leave the row unsplittable by field number. `day`'s own format is therefore
byte-identical to what it was before readings existed -- asserted directly,
below.
$ colitur readings 2026 | head -3
2026-01-01 ef-circumcision | Titus 2:11-15 | Luke 2:21
2026-01-02 ef-christmas-1-friday | Titus 2:11-15 | Luke 2:21
2026-01-03 ef-christmas-1-saturday | Gal 4:1-7 | Luke 2:33-40
$ colitur readings 2026 | wc -l
365
2 January reads the Circumcision's own Mass, not its own: the Missal's
Mass-propers rubric printed under the Sanctissimi Nominis Iesu heading --
"Diebus ferialibus a 2 ad 5 ianuarii Missa dicitur ut die 1 ianuarii, cum
Gloria et praefatione de Nativitate, sine Credo et Communicantes proprio"
(docs/research/scan1.txt:6523-6526, corroborated scan2.txt:7216). Note this
is NOT RG 17(a), which fixes only WHEN the Holy Name is kept; the two are
different rules sharing a date window. Hence the identical citation on the
1st and the 2nd above, which is correct and not a duplicated row.
One line per step of the reading-resolution chain, the same four cases
test_golden.ml pins against the photographic scans (each literal there was
read out of the Missal before being compared with colitur -- these assert
that the CLI path agrees with the library path, nothing more):
$ colitur readings 2038 | grep '^2038-03-08 '
2038-03-08 john-of-god | Ecclus 31:8-11 | Matt 22:34-46
$ colitur readings 2026 | grep '^2026-02-23 '
2026-02-23 ef-lent-1-monday | Ezech 34:11-16 | Matt 25:31-46
$ colitur readings 2025 | grep '^2025-12-01 '
2025-12-01 ef-advent-1-monday | Rom 13:11-14 | Luke 21:25-33
$ colitur readings 2038 | grep '^2038-03-06 '
2038-03-06 sts-felicitas-perpetua | Ecclus 51:1-8, 12 | Matt 13:44-52
The Advent line above is the ferial resumption (chain step 3) and is the one
worth reading twice: 1 December 2025 is the Monday after Advent I, and
Advent's ferias -- unlike Lent's -- have no Mass of their own, so the
citation shown IS Advent I Sunday's ("ad Romanos. Rom. 13, 11-14" /
"dum Lucam. Luc. 21, 25-33", scan1.txt:4878 + 4912). A regression that
stopped walking back would change this line and nothing else.
Every day of the year carries both parts -- no "-" anywhere. This is the CLI
view of the invariant Validate asserts over the whole 1583..9999 domain
("citations" / "citations-unresolved"), so it is a spot-check of one year
rather than the guarantee itself:
$ colitur readings 2026 | grep -c ' | - \| | -$'
0
[1]
`colitur day`'s own format is unaffected by any of the above:
$ colitur day 2026 | head -1
2026-01-01 thursday christmastide - ef-circumcision class-1 white
A year outside the supported domain is rejected (exit 2):
$ colitur readings 1000
colitur: year 1000 out of range 1583..9999
[2]
An explicit COLITUR_DATA_DIR that does not hold the data is an error (exit 2),
never a silent fall-back to some other copy. A packager or operator who names
a directory has stated an intent; quietly calendaring off a different one
because theirs was wrong is the silent substitution this project refuses
everywhere else. The first version of this resolution DID fall through, and a
deliberately bogus value produced a full, plausible, entirely un-flagged year:
$ COLITUR_DATA_DIR=/nonexistent/xyz colitur readings 2026
colitur: COLITUR_DATA_DIR is set to /nonexistent/xyz, which contains no sanctoral.sexp
colitur: refusing to fall back to another data directory -- unset it, or point it at one
[2]
An empty or half-populated installed directory is a different case and DOES
fall through to the build tree: nobody stated an intent there, and a failed or
partially removed install must not shadow a working tree and then fail later
with a confusing per-file error. (Exercised directly in the task, by creating
_build/default/share/colitur/ef and confirming the year still resolves; not
reproduced here because the cram sandbox's own exe path makes the layout
awkward to stage without asserting on dune internals.)
|