aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 14:28:50 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-26 14:28:50 +0200
commite5cbc662227de4f3ab0089fe73f639f4f84601a4 (patch)
tree264b29424d2d3371f6f31f2b87ac111c74622808
parente5066c0d082a09eca3d4c8bbf8da1cc04dde9104 (diff)
downloadcolitur-e5cbc662227de4f3ab0089fe73f639f4f84601a4.tar.gz
colitur-e5cbc662227de4f3ab0089fe73f639f4f84601a4.zip
fix(citation): make the well-formed reading-part set rite-supplied
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.
-rw-r--r--data/of/lectionary.sexp228
-rw-r--r--lib/kernel/rite.ml1
-rw-r--r--lib/kernel/rite.mli36
-rw-r--r--lib/kernel/validate.ml31
-rw-r--r--lib/kernel/validate.mli22
-rw-r--r--lib/rites/rite_ef/rite_ef.ml7
-rw-r--r--lib/rites/rite_ef/rite_ef.mli5
-rw-r--r--lib/rites/rite_of/rite_of.ml13
-rw-r--r--lib/rites/rite_of/rite_of.mli7
-rw-r--r--test/test_calendar.ml11
-rw-r--r--test/test_citation_coverage_of.ml31
-rw-r--r--test/test_lectionary_of.ml12
-rw-r--r--test/test_validate.ml73
-rw-r--r--tools/bootstrap_lectionary_of.ml136
14 files changed, 538 insertions, 75 deletions
diff --git a/data/of/lectionary.sexp b/data/of/lectionary.sexp
index 437cada..7fe5b24 100644
--- a/data/of/lectionary.sexp
+++ b/data/of/lectionary.sexp
@@ -1,6 +1,7 @@
; data/of/lectionary.sexp -- OF (2002) temporal + sanctoral lectionary
-; (Epistle + Gospel citations, never scripture text), bootstrapped from
-; lectio.
+; (First, and on Sundays/solemnities also Second, and Gospel citations,
+; never scripture text -- "Epistle" is EF vocabulary, not used here),
+; bootstrapped from lectio.
;
; LINEAGE, stated loudly because it constrains what this file can show
; (design spec 2026-08-24-colitur-of-rite-module-design.md sec4.4/sec5):
@@ -48,6 +49,19 @@
; three genuinely different structural-unreachability reasons, none of
; them "duplicate" -- see [excluded_bases]'s own comment.
;
+; CORRECTED, fix wave I7 (final-review.md, 2026-08-25-colitur-of-
+; phases-3-5, 2026-08-26): this file used to carry First and Gospel
+; only, and called the First reading an "Epistle" above -- EF
+; vocabulary, wrong for the OF (its First reading is often Old
+; Testament or Acts, not an epistle at all; OLM 1981 Praenotanda
+; n. 66.1). Both fixed at the source: {!Colitur_kernel.Rite
+; .t.citation_shapes} (kernel change, {!Rite_of.Rite_of.context}'s own
+; citation) makes the well-formed citation-part shape RITE-supplied
+; rather than a kernel-hardcoded [[First; Gospel]], and [cite] above
+; now extracts a Second reading from every SUNDAY-CYCLE (Sunday/
+; solemnity) entry lectio's own snapshot carries one for. See
+; COVERAGE (5) below for the measured count.
+;
; Source: ../lectio/internal/caldata/of-lectionary.ini
; SHA-256: f0b527aef58b93e6ccdfbeafe52b340ed2a9d7d72805bf5083e3da04b080123c
; 988 ini sections (988 expected) -> 438 resolved (base, cycle-shape) pairs -> 435 colitur slugs mapped, 3 ini bases genuinely excluded (structurally
@@ -76,8 +90,8 @@
; OLM norms working as designed for a saint with no proper of
; their own, not a gap in this data.
; (4) Citation-siglum conversion (fix wave I2, 2026-08-26 review): of
-; 1542 emitted (First, Gospel) citation fields, 41 distinct
-; references (out of the full 1542) do not parse -- every one a
+; 1725 emitted (First, Second, Gospel) citation fields, 49 distinct
+; references (out of the full 1725) do not parse -- every one a
; hyphen range that crosses a chapter boundary ("2:29-3:6"), a
; {!Colitur_citation.Parse.t} shape this parser's [part]/
; [verse_range] types do not represent, deliberately not built
@@ -89,19 +103,39 @@
; .format}'s own documented contract on a parse miss. Pinned
; exactly, both directions, by test/test_citation_coverage_of.ml.
; Named below.
+; (5) Second-reading coverage (fix wave I7, 2026-08-26): 183 of the
+; 1725 emitted citation fields above are a Second reading -- every
+; one from a SUNDAY-CYCLE (-A/-B/-C, i.e. Sunday/solemnity)
+; entry, never a weekday-cycle one ([cite]'s own
+; [~is_sunday_cycle] guard), matching OLM 1981 Praenotanda
+; n. 66.1/n. 69.1 and n. 84(b)/(c) (docs/research/of/olm-1981
+; .pdf pp.32-33,37-38/"XXXII-XXXIII","XXXVII-XXXVIII"): a
+; Sunday or solemnity Mass has three readings, a feria/feast/
+; memorial two. The Responsorial Psalm (lectio's own [psalm]
+; field, present on nearly every section) is deliberately NOT
+; extracted -- see [cite]'s own doc comment for the argument
+; (a chant, not a reading; declared in neither rite's
+; {!Colitur_kernel.Rite.t.citation_shapes}).
; Regenerate with:
; eval $(opam env) && dune exec tools/bootstrap_lectionary_of.exe -- ../lectio/internal/caldata/of-lectionary.ini data/of/lectionary.sexp
; Unmapped lectio bases (0):
-; Citations that do not parse (41 distinct, all chapter-crossing ranges):
+; Citations that do not parse (49 distinct, all chapter-crossing ranges):
+; 1 Corinthians 10:31-11:1
; 1 Corinthians 12:31-13:13
; 1 John 1:5-2:2
; 1 John 2:29-3:6
; 1 John 3:22-4:6
; 1 John 4:19-5:4
+; 1 Thessalonians 3:12-4:2
; 2 Corinthians 3:15-4:1,3-6
+; 2 Corinthians 4:13-5:1
; 2 Samuel 18:9-10,14b,24-25a,30-19:3
+; 2 Thessalonians 1:11-2:2
+; 2 Thessalonians 2:16-3:5
+; 2 Timothy 3:14-4:2
; Colossians 1:24-2:3
; Ecclesiastes 11:9-12:8
+; Ephesians 4:30-5:2
; Ephesians 4:32-5:8
; Exodus 11:10-12:14
; Exodus 14:21-15:1
@@ -113,6 +147,7 @@
; Hebrews 7:25-8:6
; Isaiah 52:13-53:12
; Isaiah 8:23b-9:3
+; James 3:16-4:3
; John 15:26-16:4a
; John 18:1-19:42
; Jonah 1:1-2:2,11
@@ -144,6 +179,7 @@
((part Gospel) (reference "Luke 23:44-46,50,52-53"))))
(andrew-the-apostle
(((part First) (reference "Isaiah 49:1-6"))
+ ((part Second) (reference "Romans 10:9-18"))
((part Gospel) (reference "Mat 4:18-22"))))
(annunciation-of-the-lord
(((part First) (reference "Isaiah 7:10-14;8:10"))
@@ -159,6 +195,7 @@
((part Gospel) (reference "Luke 1:5-17"))))
(birth-of-the-blessed-virgin-mary
(((part First) (reference "Micah 5:1-4"))
+ ((part Second) (reference "Romans 8:28-30"))
((part Gospel) (reference "Mat 1:18-23"))))
(chair-of-saint-peter-apostle
(((part First) (reference "1 Peter 5:1-4"))
@@ -192,6 +229,7 @@
((part Gospel) (reference "Mark 16:15-20"))))
(mary-magdalene
(((part First) (reference "Song of Solomon 8:6-7"))
+ ((part Second) (reference "2 Corinthians 5:14-17"))
((part Gospel) (reference "John 20:1,11-18"))))
(matthew-the-evangelist-apostle-evangelist
(((part First) (reference "Ephesians 4:1-7,11-13"))
@@ -312,69 +350,90 @@
((part Gospel) (reference "Luke 1:67-79"))))
(of-advent-sunday-1-a
(((part First) (reference "Isaiah 2:1-5"))
+ ((part Second) (reference "Romans 13:11-14"))
((part Gospel) (reference "Matthew 24:37-44"))))
(of-advent-sunday-1-b
(((part First) (reference "Isaiah 63:16b-17,19b;64:2-7"))
+ ((part Second) (reference "1 Corinthians 1:3-9"))
((part Gospel) (reference "Mark 13:33-37"))))
(of-advent-sunday-1-c
(((part First) (reference "Jeremiah 33:14-16"))
+ ((part Second) (reference "1 Thessalonians 3:12-4:2"))
((part Gospel) (reference "Luke 21:25-28,34-36"))))
(of-advent-sunday-2-a
(((part First) (reference "Isaiah 11:1-10"))
+ ((part Second) (reference "Romans 15:4-9"))
((part Gospel) (reference "Matthew 3:1-12"))))
(of-advent-sunday-2-b
(((part First) (reference "Isaiah 40:1-5,9-11"))
+ ((part Second) (reference "2 Peter 3:8-14"))
((part Gospel) (reference "Mark 1:1-8"))))
(of-advent-sunday-2-c
(((part First) (reference "Baruch 5:1-9"))
+ ((part Second) (reference "Philippians 1:4-6,8-11"))
((part Gospel) (reference "Luke 3:1-6"))))
(of-advent-sunday-3-a
(((part First) (reference "Isaiah 35:1-6a,10"))
+ ((part Second) (reference "James 5:7-10"))
((part Gospel) (reference "Matthew 11:2-11"))))
(of-advent-sunday-3-b
(((part First) (reference "Isaiah 61:1-2a,10-11"))
+ ((part Second) (reference "1 Thessalonians 5:16-24"))
((part Gospel) (reference "John 1:6-8,19-28"))))
(of-advent-sunday-3-c
(((part First) (reference "Zephaniah 3:14-18a"))
+ ((part Second) (reference "Philippians 4:4-7"))
((part Gospel) (reference "Luke 3:10-18"))))
(of-advent-sunday-4-a
(((part First) (reference "Isaiah 7:10-14"))
+ ((part Second) (reference "Romans 1:1-7"))
((part Gospel) (reference "Matthew 1:18-24"))))
(of-advent-sunday-4-b
(((part First) (reference "2 Samuel 7:1-5,8b-12,14a,16"))
+ ((part Second) (reference "Romans 16:25-27"))
((part Gospel) (reference "Luke 1:26-38"))))
(of-advent-sunday-4-c
(((part First) (reference "Micah 5:1-4a"))
+ ((part Second) (reference "Hebrews 10:5-10"))
((part Gospel) (reference "Luke 1:39-45"))))
(of-ascension-a
(((part First) (reference "The Acts 1:1-11"))
+ ((part Second) (reference "Ephesians 1:17-23"))
((part Gospel) (reference "Matthew 28:16-20"))))
(of-ascension-b
(((part First) (reference "The Acts 1:1-11"))
+ ((part Second) (reference "Ephesians 4:1-13"))
((part Gospel) (reference "Mark 16:15-20"))))
(of-ascension-c
(((part First) (reference "The Acts 1:1-11"))
+ ((part Second) (reference "Hebrews 9:24-28;10:19-23"))
((part Gospel) (reference "Luke 24:46-53"))))
(of-ash-wednesday
(((part First) (reference "Joel 2:12-18"))
((part Gospel) (reference "Matthew 6:1-6,16-18"))))
(of-baptism-of-the-lord-a
(((part First) (reference "Isaiah 42:1-4,6-7"))
+ ((part Second) (reference "The Acts 10:34-38"))
((part Gospel) (reference "Matthew 3:13-17"))))
(of-baptism-of-the-lord-b
(((part First) (reference "Isaiah 55:1-11"))
+ ((part Second) (reference "1 John 5:1-9"))
((part Gospel) (reference "Mark 1:7-11"))))
(of-baptism-of-the-lord-c
(((part First) (reference "Isaiah 40:1-5,9-11"))
+ ((part Second) (reference "Titus 2:11-14;3:4-7"))
((part Gospel) (reference "Luke 3:15-16,21-22"))))
(of-christ-the-king-a
(((part First) (reference "Ezekiel 34:11-12,15-17"))
+ ((part Second) (reference "1 Corinthians 15:20-26,28"))
((part Gospel) (reference "Matthew 25:31-46"))))
(of-christ-the-king-b
(((part First) (reference "Daniel 7:13-14"))
+ ((part Second) (reference "Revelation 1:5-8"))
((part Gospel) (reference "John 18:33b-37"))))
(of-christ-the-king-c
(((part First) (reference "2 Samuel 5:1-3"))
+ ((part Second) (reference "Colossians 1:12-20"))
((part Gospel) (reference "Luke 23:35-43"))))
(of-christmas-0-friday-ii
(((part First) (reference "1 John 2:18-21"))
@@ -489,15 +548,19 @@
((part Gospel) (reference "John 2:1-11"))))
(of-christmas-sunday-2
(((part First) (reference "Sirach 24:1-4,12-16"))
+ ((part Second) (reference "Ephesians 1:3-6,15-18"))
((part Gospel) (reference "John 1:1-18"))))
(of-corpus-christi-a
(((part First) (reference "Deuteronomy 8:2-3,14b-16a"))
+ ((part Second) (reference "1 Corinthians 10:16-17"))
((part Gospel) (reference "John 6:51-58"))))
(of-corpus-christi-b
(((part First) (reference "Exodus 24:3-8"))
+ ((part Second) (reference "Hebrews 9:11-15"))
((part Gospel) (reference "Mark 14:12-16,22-26"))))
(of-corpus-christi-c
(((part First) (reference "Genesis 14:18-20"))
+ ((part Second) (reference "1 Corinthians 11:23-26"))
((part Gospel) (reference "Luke 9:11b-17"))))
(of-easter-2-friday
(((part First) (reference "The Acts 5:34-42"))
@@ -624,72 +687,95 @@
((part Gospel) (reference "Mark 16:9-15"))))
(of-easter-sunday
(((part First) (reference "The Acts 10:34a,37-43"))
+ ((part Second) (reference "Colossians 3:1-4"))
((part Gospel) (reference "John 20:1-9"))))
(of-easter-sunday-2-a
(((part First) (reference "The Acts 2:42-47"))
+ ((part Second) (reference "1 Peter 1:3-9"))
((part Gospel) (reference "John 20:19-31"))))
(of-easter-sunday-2-b
(((part First) (reference "The Acts 4:32-35"))
+ ((part Second) (reference "1 John 5:1-6"))
((part Gospel) (reference "John 20:19-31"))))
(of-easter-sunday-2-c
(((part First) (reference "The Acts 5:12-16"))
+ ((part Second) (reference "Revelation 1:9-11a,12-13,17-19"))
((part Gospel) (reference "John 20:19-31"))))
(of-easter-sunday-3-a
(((part First) (reference "The Acts 2:14,22-33"))
+ ((part Second) (reference "1 Peter 1:17-21"))
((part Gospel) (reference "Luke 24:13-35"))))
(of-easter-sunday-3-b
(((part First) (reference "The Acts 3:13-15,17-19"))
+ ((part Second) (reference "1 John 2:1-5a"))
((part Gospel) (reference "Luke 24:35-48"))))
(of-easter-sunday-3-c
(((part First) (reference "The Acts 5:27-32,40b-41"))
+ ((part Second) (reference "Revelation 5:11-14"))
((part Gospel) (reference "John 21:1-19"))))
(of-easter-sunday-4-a
(((part First) (reference "The Acts 2:14a,36-41"))
+ ((part Second) (reference "1 Peter 2:20b-25"))
((part Gospel) (reference "John 10:1-10"))))
(of-easter-sunday-4-b
(((part First) (reference "The Acts 4:8-12"))
+ ((part Second) (reference "1 John 3:1-2"))
((part Gospel) (reference "John 10:11-18"))))
(of-easter-sunday-4-c
(((part First) (reference "The Acts 13:14,43-52"))
+ ((part Second) (reference "Revelation 7:9,14b-17"))
((part Gospel) (reference "John 10:27-30"))))
(of-easter-sunday-5-a
(((part First) (reference "The Acts 6:1-7"))
+ ((part Second) (reference "1 Peter 2:4-9"))
((part Gospel) (reference "John 14:1-12"))))
(of-easter-sunday-5-b
(((part First) (reference "The Acts 9:26-31"))
+ ((part Second) (reference "1 John 3:18-24"))
((part Gospel) (reference "John 15:1-8"))))
(of-easter-sunday-5-c
(((part First) (reference "The Acts 14:21-27"))
+ ((part Second) (reference "Revelation 21:1-5a"))
((part Gospel) (reference "John 13:31-33a,34-35"))))
(of-easter-sunday-6-a
(((part First) (reference "The Acts 8:5-8,14-17"))
+ ((part Second) (reference "1 Peter 3:15-18"))
((part Gospel) (reference "John 14:15-21"))))
(of-easter-sunday-6-b
(((part First) (reference "The Acts 10:25-26,34-35,44-48"))
+ ((part Second) (reference "1 John 4:7-10"))
((part Gospel) (reference "John 15:9-17"))))
(of-easter-sunday-6-c
(((part First) (reference "The Acts 15:1-2,22-29"))
+ ((part Second) (reference "Revelation 21:10-14,22-23"))
((part Gospel) (reference "John 14:23-29"))))
(of-easter-sunday-7-a
(((part First) (reference "The Acts 1:12-14"))
+ ((part Second) (reference "1 Peter 4:13-16"))
((part Gospel) (reference "John 17:1-11a"))))
(of-easter-sunday-7-b
(((part First) (reference "The Acts 1:15-17,20a,20c-26"))
+ ((part Second) (reference "1 John 4:11-16"))
((part Gospel) (reference "John 17:11b-19"))))
(of-easter-sunday-7-c
(((part First) (reference "The Acts 7:55-60"))
+ ((part Second) (reference "Revelation 22:12-14,16-17,20"))
((part Gospel) (reference "John 17:20-26"))))
(of-epiphany
(((part First) (reference "Isaiah 60:1-6"))
+ ((part Second) (reference "Ephesians 3:2-3a,5-6"))
((part Gospel) (reference "Matthew 2:1-12"))))
(of-holy-family-a
(((part First) (reference "Sirach 3:3-7,14-17a"))
+ ((part Second) (reference "Colossians 3:12-21"))
((part Gospel) (reference "Matthew 2:13-15,19-23"))))
(of-holy-family-b
(((part First) (reference "Genesis 15:1-6;21:1-3"))
+ ((part Second) (reference "Hebrews 11:8,11-12,17-19"))
((part Gospel) (reference "Luke 2:22-40"))))
(of-holy-family-c
(((part First) (reference "1 Samuel 1:20-22,24-28"))
+ ((part Second) (reference "1 John 3:1-2,21-24"))
((part Gospel) (reference "Luke 2:41-52"))))
(of-lent-1-friday
(((part First) (reference "Ezekiel 18:21-28"))
@@ -789,6 +875,7 @@
((part Gospel) (reference "John 12:1-11"))))
(of-lent-6-saturday
(((part First) (reference "Genesis 1:1-2:2"))
+ ((part Second) (reference "Genesis 1:1,26-31"))
((part Gospel) (reference "Mat 28:1-10"))))
(of-lent-6-thursday
(((part First) (reference "Isaiah 61:1-3,6,8-9"))
@@ -810,54 +897,71 @@
((part Gospel) (reference "Luke 9:22-25"))))
(of-lent-sunday-1-a
(((part First) (reference "Genesis 2:7-9;3:1-7"))
+ ((part Second) (reference "Romans 5:12-19"))
((part Gospel) (reference "Matthew 4:1-11"))))
(of-lent-sunday-1-b
(((part First) (reference "Genesis 9:8-15"))
+ ((part Second) (reference "1 Peter 3:18-22"))
((part Gospel) (reference "Mark 1:12-15"))))
(of-lent-sunday-1-c
(((part First) (reference "Deuteronomy 26:4-10"))
+ ((part Second) (reference "Romans 10:8-13"))
((part Gospel) (reference "Luke 4:1-13"))))
(of-lent-sunday-2-a
(((part First) (reference "Genesis 12:1-4a"))
+ ((part Second) (reference "2 Timothy 1:8b-10"))
((part Gospel) (reference "Matthew 17:1-9"))))
(of-lent-sunday-2-b
(((part First) (reference "Genesis 22:1-2,9a,10-13,15-18"))
+ ((part Second) (reference "Romans 8:31b-34"))
((part Gospel) (reference "Mark 9:2-10"))))
(of-lent-sunday-2-c
(((part First) (reference "Genesis 15:5-12,17-18"))
+ ((part Second) (reference "Philippians 3:17-4:1"))
((part Gospel) (reference "Luke 9:28b-36"))))
(of-lent-sunday-3-a
(((part First) (reference "Exodus 17:3-7"))
+ ((part Second) (reference "Romans 5:1-2,5-8"))
((part Gospel) (reference "John 4:5-42"))))
(of-lent-sunday-3-b
(((part First) (reference "Exodus 20:1-17"))
+ ((part Second) (reference "1 Corinthians 1:22-25"))
((part Gospel) (reference "John 2:13-25"))))
(of-lent-sunday-3-c
(((part First) (reference "Exodus 3:1-8a,13-15"))
+ ((part Second) (reference "1 Corinthians 10:1-6,10-12"))
((part Gospel) (reference "Luke 13:1-9"))))
(of-lent-sunday-4-a
(((part First) (reference "1 Samuel 16:1b,6-7,10-13a"))
+ ((part Second) (reference "Ephesians 5:8-14"))
((part Gospel) (reference "John 9:1-41"))))
(of-lent-sunday-4-b
(((part First) (reference "2 Chronicles 36:14-16,19-23"))
+ ((part Second) (reference "Ephesians 2:4-10"))
((part Gospel) (reference "John 3:14-21"))))
(of-lent-sunday-4-c
(((part First) (reference "Joshua 5:9a,10-12"))
+ ((part Second) (reference "2 Corinthians 5:17-21"))
((part Gospel) (reference "Luke 15:1-3,11-32"))))
(of-lent-sunday-5-a
(((part First) (reference "Ezekiel 37:12-14"))
+ ((part Second) (reference "Romans 8:8-11"))
((part Gospel) (reference "John 11:1-45"))))
(of-lent-sunday-5-b
(((part First) (reference "Jeremiah 31:31-34"))
+ ((part Second) (reference "Hebrews 5:7-9"))
((part Gospel) (reference "John 12:20-33"))))
(of-lent-sunday-5-c
(((part First) (reference "Isaiah 43:16-21"))
+ ((part Second) (reference "Philippians 3:8-14"))
((part Gospel) (reference "John 8:1-11"))))
(of-mary-mother-of-god
(((part First) (reference "Numbers 6:22-27"))
+ ((part Second) (reference "Galatians 4:4-7"))
((part Gospel) (reference "Luke 2:16-21"))))
(of-nativity
(((part First) (reference "Isaiah 52:7-10"))
+ ((part Second) (reference "Hebrews 1:1-6"))
((part Gospel) (reference "John 1:1-18"))))
(of-nativity-vigil
(((part First) (reference "Isaiah 62:1-5"))
@@ -2088,333 +2192,442 @@
((part Gospel) (reference "Mark 12:18-27"))))
(of-ordinary-time-sunday-10-a
(((part First) (reference "Hosea 6:3-6"))
+ ((part Second) (reference "Romans 4:18-25"))
((part Gospel) (reference "Matthew 9:9-13"))))
(of-ordinary-time-sunday-10-b
(((part First) (reference "Genesis 3:9-15"))
+ ((part Second) (reference "2 Corinthians 4:13-5:1"))
((part Gospel) (reference "Mark 3:20-35"))))
(of-ordinary-time-sunday-10-c
(((part First) (reference "1 Kings 17:17-24"))
+ ((part Second) (reference "Galatians 1:11-19"))
((part Gospel) (reference "Luke 7:11-17"))))
(of-ordinary-time-sunday-11-a
(((part First) (reference "Exodus 19:2-6a"))
+ ((part Second) (reference "Romans 5:6-11"))
((part Gospel) (reference "Matthew 9:36-10:8"))))
(of-ordinary-time-sunday-11-b
(((part First) (reference "Ezekiel 17:22-24"))
+ ((part Second) (reference "2 Corinthians 5:6-10"))
((part Gospel) (reference "Mark 4:26-34"))))
(of-ordinary-time-sunday-11-c
(((part First) (reference "2 Samuel 12:7-10,13"))
+ ((part Second) (reference "Galatians 2:16,19-21"))
((part Gospel) (reference "Luke 7:36-8:3"))))
(of-ordinary-time-sunday-12-a
(((part First) (reference "Jeremiah 20:10-13"))
+ ((part Second) (reference "Romans 5:12-15"))
((part Gospel) (reference "Matthew 10:26-33"))))
(of-ordinary-time-sunday-12-b
(((part First) (reference "Job 38:1,8-11"))
+ ((part Second) (reference "2 Corinthians 5:14-17"))
((part Gospel) (reference "Mark 4:35-41"))))
(of-ordinary-time-sunday-12-c
(((part First) (reference "Zechariah 12:10-11;13:1"))
+ ((part Second) (reference "Galatians 3:26-29"))
((part Gospel) (reference "Luke 9:18-24"))))
(of-ordinary-time-sunday-13-a
(((part First) (reference "2 Kings 4:8-11,14-16a"))
+ ((part Second) (reference "Romans 6:3-4,8-11"))
((part Gospel) (reference "Matthew 10:37-42"))))
(of-ordinary-time-sunday-13-b
(((part First) (reference "Wisdom 1:13-15;2:23-24"))
+ ((part Second) (reference "2 Corinthians 8:7,9,13-15"))
((part Gospel) (reference "Mark 5:21-43"))))
(of-ordinary-time-sunday-13-c
(((part First) (reference "1 Kings 19:16b,19-21"))
+ ((part Second) (reference "Galatians 5:1,13-18"))
((part Gospel) (reference "Luke 9:51-62"))))
(of-ordinary-time-sunday-14-a
(((part First) (reference "Zechariah 9:9-10"))
+ ((part Second) (reference "Romans 8:9,11-13"))
((part Gospel) (reference "Matthew 11:25-30"))))
(of-ordinary-time-sunday-14-b
(((part First) (reference "Ezekiel 2:2-5"))
+ ((part Second) (reference "2 Corinthians 12:7-10"))
((part Gospel) (reference "Mark 6:1-6"))))
(of-ordinary-time-sunday-14-c
(((part First) (reference "Isaiah 66:10-14c"))
+ ((part Second) (reference "Galatians 6:14-18"))
((part Gospel) (reference "Luke 10:1-12,17-20"))))
(of-ordinary-time-sunday-15-a
(((part First) (reference "Isaiah 55:10-11"))
+ ((part Second) (reference "Romans 8:18-23"))
((part Gospel) (reference "Matthew 13:1-23"))))
(of-ordinary-time-sunday-15-b
(((part First) (reference "Amos 7:12-15"))
+ ((part Second) (reference "Ephesians 1:3-14"))
((part Gospel) (reference "Mark 6:7-13"))))
(of-ordinary-time-sunday-15-c
(((part First) (reference "Deuteronomy 30:10-14"))
+ ((part Second) (reference "Colossians 1:15-20"))
((part Gospel) (reference "Luke 10:25-37"))))
(of-ordinary-time-sunday-16-a
(((part First) (reference "Wisdom 12:13,16-19"))
+ ((part Second) (reference "Romans 8:26-27"))
((part Gospel) (reference "Matthew 13:24-43"))))
(of-ordinary-time-sunday-16-b
(((part First) (reference "Jeremiah 23:1-6"))
+ ((part Second) (reference "Ephesians 2:13-18"))
((part Gospel) (reference "Mark 6:30-34"))))
(of-ordinary-time-sunday-16-c
(((part First) (reference "Genesis 18:1-10a"))
+ ((part Second) (reference "Colossians 1:24-28"))
((part Gospel) (reference "Luke 10:38-42"))))
(of-ordinary-time-sunday-17-a
(((part First) (reference "1 Kings 3:5,7-12"))
+ ((part Second) (reference "Romans 8:28-30"))
((part Gospel) (reference "Matthew 13:44-52"))))
(of-ordinary-time-sunday-17-b
(((part First) (reference "2 Kings 4:42-44"))
+ ((part Second) (reference "Ephesians 4:1-6"))
((part Gospel) (reference "John 6:1-15"))))
(of-ordinary-time-sunday-17-c
(((part First) (reference "Genesis 18:20-32"))
+ ((part Second) (reference "Colossians 2:12-14"))
((part Gospel) (reference "Luke 11:1-13"))))
(of-ordinary-time-sunday-18-a
(((part First) (reference "Isaiah 55:1-3"))
+ ((part Second) (reference "Romans 8:35,37-39"))
((part Gospel) (reference "Matthew 14:13-21"))))
(of-ordinary-time-sunday-18-b
(((part First) (reference "Exodus 16:2-4,12-15"))
+ ((part Second) (reference "Ephesians 4:17,20-24"))
((part Gospel) (reference "John 6:24-35"))))
(of-ordinary-time-sunday-18-c
(((part First) (reference "Ecclesiastes 1:2;2:21-23"))
+ ((part Second) (reference "Colossians 3:1-5,9-11"))
((part Gospel) (reference "Luke 12:13-21"))))
(of-ordinary-time-sunday-19-a
(((part First) (reference "1 Kings 19:9a,11-13a"))
+ ((part Second) (reference "Romans 9:1-5"))
((part Gospel) (reference "Matthew 14:22-33"))))
(of-ordinary-time-sunday-19-b
(((part First) (reference "1 Kings 19:4-8"))
+ ((part Second) (reference "Ephesians 4:30-5:2"))
((part Gospel) (reference "John 6:41-51"))))
(of-ordinary-time-sunday-19-c
(((part First) (reference "Wisdom 18:6-9"))
+ ((part Second) (reference "Hebrews 11:1-2,8-19"))
((part Gospel) (reference "Luke 12:32-48"))))
(of-ordinary-time-sunday-2-a
(((part First) (reference "Isaiah 49:3,5-6"))
+ ((part Second) (reference "1 Corinthians 1:1-3"))
((part Gospel) (reference "John 1:29-34"))))
(of-ordinary-time-sunday-2-b
(((part First) (reference "1 Samuel 3:3b-10,19"))
+ ((part Second) (reference "1 Corinthians 6:13c-15a,17-20"))
((part Gospel) (reference "John 1:35-42"))))
(of-ordinary-time-sunday-2-c
(((part First) (reference "Isaiah 62:1-5"))
+ ((part Second) (reference "1 Corinthians 12:4-11"))
((part Gospel) (reference "John 2:1-11"))))
(of-ordinary-time-sunday-20-a
(((part First) (reference "Isaiah 56:1,6-7"))
+ ((part Second) (reference "Romans 11:13-15,29-32"))
((part Gospel) (reference "Matthew 15:21-28"))))
(of-ordinary-time-sunday-20-b
(((part First) (reference "Proverbs 9:1-6"))
+ ((part Second) (reference "Ephesians 5:15-20"))
((part Gospel) (reference "John 6:51-58"))))
(of-ordinary-time-sunday-20-c
(((part First) (reference "Jeremiah 38:4-6,8-10"))
+ ((part Second) (reference "Hebrews 12:1-4"))
((part Gospel) (reference "Luke 12:49-53"))))
(of-ordinary-time-sunday-21-a
(((part First) (reference "Isaiah 22:19-23"))
+ ((part Second) (reference "Romans 11:33-36"))
((part Gospel) (reference "Matthew 16:13-20"))))
(of-ordinary-time-sunday-21-b
(((part First) (reference "Joshua 24:1-2a,15-17,18b"))
+ ((part Second) (reference "Ephesians 5:21-32"))
((part Gospel) (reference "John 6:60-69"))))
(of-ordinary-time-sunday-21-c
(((part First) (reference "Isaiah 66:18-21"))
+ ((part Second) (reference "Hebrews 12:5-7,11-13"))
((part Gospel) (reference "Luke 13:22-30"))))
(of-ordinary-time-sunday-22-a
(((part First) (reference "Jeremiah 20:7-9"))
+ ((part Second) (reference "Romans 12:1-2"))
((part Gospel) (reference "Matthew 16:21-27"))))
(of-ordinary-time-sunday-22-b
(((part First) (reference "Deuteronomy 4:1-2,6-8"))
+ ((part Second) (reference "James 1:17-18,21b-22,27"))
((part Gospel) (reference "Mark 7:1-8,14-15,21-23"))))
(of-ordinary-time-sunday-22-c
(((part First) (reference "Sirach 3:17-18,20,28-29"))
+ ((part Second) (reference "Hebrews 12:18-19,22-24a"))
((part Gospel) (reference "Luke 14:1,7-14"))))
(of-ordinary-time-sunday-23-a
(((part First) (reference "Ezekiel 33:7-9"))
+ ((part Second) (reference "Romans 13:8-10"))
((part Gospel) (reference "Matthew 18:15-20"))))
(of-ordinary-time-sunday-23-b
(((part First) (reference "Isaiah 35:4-7a"))
+ ((part Second) (reference "James 2:1-5"))
((part Gospel) (reference "Mark 7:31-37"))))
(of-ordinary-time-sunday-23-c
(((part First) (reference "Wisdom 9:13-18b"))
+ ((part Second) (reference "Philemon 9-10,12-17"))
((part Gospel) (reference "Luke 14:25-33"))))
(of-ordinary-time-sunday-24-a
(((part First) (reference "Sirach 27:30-28:7"))
+ ((part Second) (reference "Romans 14:7-9"))
((part Gospel) (reference "Matthew 18:21-35"))))
(of-ordinary-time-sunday-24-b
(((part First) (reference "Isaiah 50:4-9a"))
+ ((part Second) (reference "James 2:14-18"))
((part Gospel) (reference "Mark 8:27-35"))))
(of-ordinary-time-sunday-24-c
(((part First) (reference "Exodus 32:7-11,13-14"))
+ ((part Second) (reference "1 Timothy 1:12-17"))
((part Gospel) (reference "Luke 15:1-32"))))
(of-ordinary-time-sunday-25-a
(((part First) (reference "Isaiah 55:6-9"))
+ ((part Second) (reference "Philippians 1:20c-24,27a"))
((part Gospel) (reference "Matthew 20:1-16a"))))
(of-ordinary-time-sunday-25-b
(((part First) (reference "Wisdom 2:12,17-20"))
+ ((part Second) (reference "James 3:16-4:3"))
((part Gospel) (reference "Mark 9:30-37"))))
(of-ordinary-time-sunday-25-c
(((part First) (reference "Amos 8:4-7"))
+ ((part Second) (reference "1 Timothy 2:1-8"))
((part Gospel) (reference "Luke 16:1-13"))))
(of-ordinary-time-sunday-26-a
(((part First) (reference "Ezekiel 18:25-28"))
+ ((part Second) (reference "Philippians 2:1-11"))
((part Gospel) (reference "Matthew 21:28-32"))))
(of-ordinary-time-sunday-26-b
(((part First) (reference "Numbers 11:25-29"))
+ ((part Second) (reference "James 5:1-6"))
((part Gospel) (reference "Mark 9:38-43,45,47-48"))))
(of-ordinary-time-sunday-26-c
(((part First) (reference "Amos 6:1a,4-7"))
+ ((part Second) (reference "1 Timothy 6:11-16"))
((part Gospel) (reference "Luke 16:19-31"))))
(of-ordinary-time-sunday-27-a
(((part First) (reference "Isaiah 5:1-7"))
+ ((part Second) (reference "Philippians 4:6-9"))
((part Gospel) (reference "Matthew 21:33-43"))))
(of-ordinary-time-sunday-27-b
(((part First) (reference "Genesis 2:18-24"))
+ ((part Second) (reference "Hebrews 2:9-11"))
((part Gospel) (reference "Mark 10:2-16"))))
(of-ordinary-time-sunday-27-c
(((part First) (reference "Habakkuk 1:2-3;2:2-4"))
+ ((part Second) (reference "2 Timothy 1:6-8,13-14"))
((part Gospel) (reference "Luke 17:5-10"))))
(of-ordinary-time-sunday-28-a
(((part First) (reference "Isaiah 25:6-10a"))
+ ((part Second) (reference "Philippians 4:12-14,19-20"))
((part Gospel) (reference "Matthew 22:1-14"))))
(of-ordinary-time-sunday-28-b
(((part First) (reference "Wisdom 7:7-11"))
+ ((part Second) (reference "Hebrews 4:12-13"))
((part Gospel) (reference "Mark 10:17-30"))))
(of-ordinary-time-sunday-28-c
(((part First) (reference "2 Kings 5:14-17"))
+ ((part Second) (reference "2 Timothy 2:8-13"))
((part Gospel) (reference "Luke 17:11-19"))))
(of-ordinary-time-sunday-29-a
(((part First) (reference "Isaiah 45:1,4-6"))
+ ((part Second) (reference "1 Thessalonians 1:1-5b"))
((part Gospel) (reference "Matthew 22:15-21"))))
(of-ordinary-time-sunday-29-b
(((part First) (reference "Isaiah 53:10-11"))
+ ((part Second) (reference "Hebrews 4:14-16"))
((part Gospel) (reference "Mark 10:35-45"))))
(of-ordinary-time-sunday-29-c
(((part First) (reference "Exodus 17:8-13"))
+ ((part Second) (reference "2 Timothy 3:14-4:2"))
((part Gospel) (reference "Luke 18:1-8"))))
(of-ordinary-time-sunday-3-a
(((part First) (reference "Isaiah 8:23b-9:3"))
+ ((part Second) (reference "1 Corinthians 1:10-13,17"))
((part Gospel) (reference "Matthew 4:12-23"))))
(of-ordinary-time-sunday-3-b
(((part First) (reference "Jonah 3:1-5,10"))
+ ((part Second) (reference "1 Corinthians 7:29-31"))
((part Gospel) (reference "Mark 1:14-20"))))
(of-ordinary-time-sunday-3-c
(((part First) (reference "Nehemiah 8:2-4a,5-6,8-10"))
+ ((part Second) (reference "1 Corinthians 12:12-30"))
((part Gospel) (reference "Luke 1:1-4;4:14-21"))))
(of-ordinary-time-sunday-30-a
(((part First) (reference "Exodus 22:20-26"))
+ ((part Second) (reference "1 Thessalonians 1:5c-10"))
((part Gospel) (reference "Matthew 22:34-40"))))
(of-ordinary-time-sunday-30-b
(((part First) (reference "Jeremiah 31:7-9"))
+ ((part Second) (reference "Hebrews 5:1-6"))
((part Gospel) (reference "Mark 10:46-52"))))
(of-ordinary-time-sunday-30-c
(((part First) (reference "Sirach 35:12-14,16-18"))
+ ((part Second) (reference "2 Timothy 4:6-8,16-18"))
((part Gospel) (reference "Luke 18:9-14"))))
(of-ordinary-time-sunday-31-a
(((part First) (reference "Malachi 1:14b-2:2b,8-10"))
+ ((part Second) (reference "1 Thessalonians 2:7b-9,13"))
((part Gospel) (reference "Matthew 23:1-12"))))
(of-ordinary-time-sunday-31-b
(((part First) (reference "Deuteronomy 6:2-6"))
+ ((part Second) (reference "Hebrews 7:23-28"))
((part Gospel) (reference "Mark 12:28b-34"))))
(of-ordinary-time-sunday-31-c
(((part First) (reference "Wisdom 11:22-12:2"))
+ ((part Second) (reference "2 Thessalonians 1:11-2:2"))
((part Gospel) (reference "Luke 19:1-10"))))
(of-ordinary-time-sunday-32-a
(((part First) (reference "Wisdom 6:12-16"))
+ ((part Second) (reference "1 Thessalonians 4:13-18"))
((part Gospel) (reference "Matthew 25:1-13"))))
(of-ordinary-time-sunday-32-b
(((part First) (reference "1 Kings 17:10-16"))
+ ((part Second) (reference "Hebrews 9:24-28"))
((part Gospel) (reference "Mark 12:38-44"))))
(of-ordinary-time-sunday-32-c
(((part First) (reference "2 Maccabees 7:1-2,9-14"))
+ ((part Second) (reference "2 Thessalonians 2:16-3:5"))
((part Gospel) (reference "Luke 20:27-38"))))
(of-ordinary-time-sunday-33-a
(((part First) (reference "Proverbs 31:10-13,19-20,30-31"))
+ ((part Second) (reference "1 Thessalonians 5:1-6"))
((part Gospel) (reference "Matthew 25:14-30"))))
(of-ordinary-time-sunday-33-b
(((part First) (reference "Daniel 12:1-3"))
+ ((part Second) (reference "Hebrews 10:11-14,18"))
((part Gospel) (reference "Mark 13:24-32"))))
(of-ordinary-time-sunday-33-c
(((part First) (reference "Malachi 4:1-2"))
+ ((part Second) (reference "2 Thessalonians 3:7-12"))
((part Gospel) (reference "Luke 21:5-19"))))
(of-ordinary-time-sunday-4-a
(((part First) (reference "Zephaniah 2:3;3:12-13"))
+ ((part Second) (reference "1 Corinthians 1:26-31"))
((part Gospel) (reference "Matthew 5:1-12a"))))
(of-ordinary-time-sunday-4-b
(((part First) (reference "Deuteronomy 18:15-20"))
+ ((part Second) (reference "1 Corinthians 7:32-35"))
((part Gospel) (reference "Mark 1:21-28"))))
(of-ordinary-time-sunday-4-c
(((part First) (reference "Jeremiah 1:4-5,17-19"))
+ ((part Second) (reference "1 Corinthians 12:31-13:13"))
((part Gospel) (reference "Luke 4:21-30"))))
(of-ordinary-time-sunday-5-a
(((part First) (reference "Isaiah 58:7-10"))
+ ((part Second) (reference "1 Corinthians 2:1-5"))
((part Gospel) (reference "Matthew 5:13-16"))))
(of-ordinary-time-sunday-5-b
(((part First) (reference "Job 7:1-4,6-7"))
+ ((part Second) (reference "1 Corinthians 9:16-19,22-23"))
((part Gospel) (reference "Mark 1:29-39"))))
(of-ordinary-time-sunday-5-c
(((part First) (reference "Isaiah 6:1-2a,3-8"))
+ ((part Second) (reference "1 Corinthians 15:1-11"))
((part Gospel) (reference "Luke 5:1-11"))))
(of-ordinary-time-sunday-6-a
(((part First) (reference "Sirach 15:16-21"))
+ ((part Second) (reference "1 Corinthians 2:6-10"))
((part Gospel) (reference "Matthew 5:17-37"))))
(of-ordinary-time-sunday-6-b
(((part First) (reference "Leviticus 13:1-2,44-46"))
+ ((part Second) (reference "1 Corinthians 10:31-11:1"))
((part Gospel) (reference "Mark 1:40-45"))))
(of-ordinary-time-sunday-6-c
(((part First) (reference "Jeremiah 17:5-8"))
+ ((part Second) (reference "1 Corinthians 15:12,16-20"))
((part Gospel) (reference "Luke 6:17,20-26"))))
(of-ordinary-time-sunday-7-a
(((part First) (reference "Leviticus 19:1-2,17-18"))
+ ((part Second) (reference "1 Corinthians 3:16-23"))
((part Gospel) (reference "Matthew 5:38-48"))))
(of-ordinary-time-sunday-7-b
(((part First) (reference "Isaiah 43:18-19,21-22,24b-25"))
+ ((part Second) (reference "2 Corinthians 1:18-22"))
((part Gospel) (reference "Mark 2:1-12"))))
(of-ordinary-time-sunday-7-c
(((part First) (reference "1 Samuel 26:2,7-9,12-13,22-23"))
+ ((part Second) (reference "1 Corinthians 15:45-49"))
((part Gospel) (reference "Luke 6:27-38"))))
(of-ordinary-time-sunday-8-a
(((part First) (reference "Isaiah 49:14-15"))
+ ((part Second) (reference "1 Corinthians 4:1-5"))
((part Gospel) (reference "Matthew 6:24-34"))))
(of-ordinary-time-sunday-8-b
(((part First) (reference "Hosea 2:16b,17b,21-22"))
+ ((part Second) (reference "2 Corinthians 3:1b-6"))
((part Gospel) (reference "Mark 2:18-22"))))
(of-ordinary-time-sunday-8-c
(((part First) (reference "Sirach 27:5-8"))
+ ((part Second) (reference "1 Corinthians 15:54-58"))
((part Gospel) (reference "Luke 6:39-45"))))
(of-ordinary-time-sunday-9-a
(((part First) (reference "Deuteronomy 11:18,26-28,32"))
+ ((part Second) (reference "Romans 3:21-25,28"))
((part Gospel) (reference "Matthew 7:21-27"))))
(of-ordinary-time-sunday-9-b
(((part First) (reference "Deuteronomy 5:12-15"))
+ ((part Second) (reference "2 Corinthians 4:6-11"))
((part Gospel) (reference "Mark 2:23-3:6"))))
(of-ordinary-time-sunday-9-c
(((part First) (reference "1 Kings 8:41-43"))
+ ((part Second) (reference "Galatians 1:1-2,6-10"))
((part Gospel) (reference "Luke 7:1-10"))))
(of-palm-sunday-a
(((part First) (reference "Isaiah 50:4-7"))
+ ((part Second) (reference "Philippians 2:6-11"))
((part Gospel) (reference "Mat 27:11-54"))))
(of-palm-sunday-b
(((part First) (reference "Isaiah 50:4-7"))
+ ((part Second) (reference "Philippians 2:6-11"))
((part Gospel) (reference "Mark 15:1-39"))))
(of-palm-sunday-c
(((part First) (reference "Isaiah 50:4-7"))
+ ((part Second) (reference "Philippians 2:6-11"))
((part Gospel) (reference "Luke 23:1-49"))))
(of-pentecost-a
(((part First) (reference "The Acts 2:1-11"))
+ ((part Second) (reference "1 Corinthians 12:3b-7,12-13"))
((part Gospel) (reference "John 20:19-23"))))
(of-pentecost-b
(((part First) (reference "The Acts 2:1-11"))
+ ((part Second) (reference "Galatians 5:16-25"))
((part Gospel) (reference "John 15:26-27;16:12-15"))))
(of-pentecost-c
(((part First) (reference "The Acts 2:1-11"))
+ ((part Second) (reference "Romans 8:8-17"))
((part Gospel) (reference "John 14:15-16,23b-26"))))
(of-trinity-a
(((part First) (reference "Exodus 34:4b-6,8-9"))
+ ((part Second) (reference "2 Corinthians 13:11-13"))
((part Gospel) (reference "John 3:16-18"))))
(of-trinity-b
(((part First) (reference "Deuteronomy 4:32-34,39-40"))
+ ((part Second) (reference "Romans 8:14-17"))
((part Gospel) (reference "Matthew 28:16-20"))))
(of-trinity-c
(((part First) (reference "Proverbs 8:22-31"))
+ ((part Second) (reference "Romans 5:1-5"))
((part Gospel) (reference "John 16:12-15"))))
(presentation-of-the-lord
(((part First) (reference "Malachi 3:1-4"))
((part Gospel) (reference "Luke 2:22-32"))))
(sacred-heart-of-jesus-a
(((part First) (reference "Deuteronomy 7:6-11"))
+ ((part Second) (reference "1 John 4:7-16"))
((part Gospel) (reference "Matthew 11:25-30"))))
(sacred-heart-of-jesus-b
(((part First) (reference "Hosea 11:1,3-4,8c-9"))
+ ((part Second) (reference "Ephesians 3:8-12,14-19"))
((part Gospel) (reference "John 19:31-37"))))
(sacred-heart-of-jesus-c
(((part First) (reference "Ezekiel 34:11-16"))
+ ((part Second) (reference "Romans 5:5b-11"))
((part Gospel) (reference "Luke 15:3-7"))))
(saints-michael-gabriel-and-raphael-archangels
(((part First) (reference "Daniel 7:9-10,13-14"))
+ ((part Second) (reference "Revelation 12:7-12"))
((part Gospel) (reference "John 1:47-51"))))
(saints-peter-and-paul-apostles
(((part First) (reference "Acts 3:1-10"))
@@ -2430,6 +2643,7 @@
((part Gospel) (reference "Mat 10:17-22"))))
(the-conversion-of-saint-paul-apostle
(((part First) (reference "Acts 22:3-16"))
+ ((part Second) (reference "Acts 9:1-22"))
((part Gospel) (reference "Mark 16:15-18"))))
(thomas-the-apostle
(((part First) (reference "Ephesians 2:19-22"))
@@ -2439,13 +2653,17 @@
((part Gospel) (reference "Mat 17:1-9"))))
(transfiguration-of-the-lord-b
(((part First) (reference "Daniel 7:9-10,13-14"))
+ ((part Second) (reference "2 Peter 1:16-19"))
((part Gospel) (reference "Mark 9:2-10"))))
(transfiguration-of-the-lord-c
(((part First) (reference "Daniel 7:9-10,13-14"))
+ ((part Second) (reference "2 Peter 1:16-19"))
((part Gospel) (reference "Luke 9:28-36"))))
(triumph-of-the-holy-cross
(((part First) (reference "Numbers 21:4-9"))
+ ((part Second) (reference "Philippians 2:6-11"))
((part Gospel) (reference "John 3:13-17"))))
(visitation-of-the-blessed-virgin-mary
(((part First) (reference "Zephaniah 3:14-17"))
+ ((part Second) (reference "Romans 12:9-16"))
((part Gospel) (reference "Luke 1:39-56")))))
diff --git a/lib/kernel/rite.ml b/lib/kernel/rite.ml
index e44c2c6..adca8fe 100644
--- a/lib/kernel/rite.ml
+++ b/lib/kernel/rite.ml
@@ -19,6 +19,7 @@ type ('s, 'r) t = {
date:Date.t ->
temporal_at:(Date.t -> ('s, 'r) Temporal.t) ->
Mass_formulary.t option * Citation.t list;
+ citation_shapes : Citation.part list list;
creed : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> bool;
gloria : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> bool;
preface : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> Preface.t option;
diff --git a/lib/kernel/rite.mli b/lib/kernel/rite.mli
index d53e4e6..ec850f8 100644
--- a/lib/kernel/rite.mli
+++ b/lib/kernel/rite.mli
@@ -100,10 +100,12 @@ type ('s, 'r) t = {
temporal_at:(Date.t -> ('s, 'r) Temporal.t) ->
Mass_formulary.t option * Citation.t list;
(** The Mass actually said -- which formulary, and how that was decided
- -- paired with its Epistle and Gospel citations. Rite-supplied for
- the same reason [transfer_target] is: what a day with no proper of
- its own falls back to is a rubric of a particular rite, not a
- universal.
+ -- paired with its reading citations (EF: Epistle and Gospel; OF:
+ First, and on Sundays/solemnities also Second, and Gospel -- see
+ {!citation_shapes} for the rite-supplied shape [Validate] holds
+ this list to). Rite-supplied for the same reason [transfer_target]
+ is: what a day with no proper of its own falls back to is a rubric
+ of a particular rite, not a universal.
The [Mass_formulary.t option] is [None] exactly when the rite's
lectionary is not built at all (the citation list is then also
@@ -119,6 +121,32 @@ type ('s, 'r) t = {
temporal identity (the preceding Sunday's, for the ferial rule)
without re-implementing the temporal cycle -- the same shape
[transfer_target]'s own [occupant] callback established. *)
+ citation_shapes : Citation.part list list;
+ (** Every well-formed shape a resolved day's [citations] may take, each
+ already sorted in {!Citation.part}'s own declaration order (the
+ order [List.sort compare] gives it, and the order {!Validate}'s own
+ ["citations"] check sorts a day's actual parts into before
+ comparing). A day passes that check when its sorted parts are
+ EMPTY (nothing resolved -- the separate ["citations-unresolved"]
+ coverage check) or equal one of these shapes EXACTLY -- no more
+ parts, no fewer, none repeated.
+
+ Generalises what used to be a single kernel-hardcoded
+ [[First; Gospel]], 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: the OF's Mass has TWO legitimate sizes, not one --
+ [[First; Gospel]] on a feria, feast or memorial, and
+ [[First; Second; Gospel]] on a Sunday or solemnity (OLM 1981
+ Praenotanda n. 66.1 vs n. 69.1, page-image verified,
+ docs/research/of/olm-1981.pdf pp.32-33/"XXXII-XXXIII": "Quaelibet
+ Missa tres exhibet lectiones" against "Quaelibet Missa duas
+ exhibet lectiones"; n. 84(b)/(c), pp.37-38/"XXXVII-XXXVIII",
+ extends the three-reading shape to every solemnity of a
+ particular calendar and confines feasts/memorials to two). EF
+ still supplies exactly the one shape it always had -- see
+ rite_ef.ml's own [citation_shapes] -- so EF's resolved output is
+ unaffected letter for letter. *)
creed : temporal:('s, 'r) Temporal.t -> observed:'r Celebration.t -> date:Date.t -> bool;
(** Whether the Creed is said, post-Gospel/homily, at this day's Mass
(EF: RG 475-476). A [bool], not an [option]: this is a decision,
diff --git a/lib/kernel/validate.ml b/lib/kernel/validate.ml
index f523b39..c7b6093 100644
--- a/lib/kernel/validate.ml
+++ b/lib/kernel/validate.ml
@@ -414,18 +414,26 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
is why it is a match on the sorted part list rather than three
separate tests:
- - zero or two, never one -- an Epistle without a Gospel, or the
- reverse, is a malformed Mass, not a partial one;
- - only [First] and [Gospel] ever appear -- the chants (Psalm,
- Second, Tract, Alleluia, Sequence) are deliberately unbuilt,
- with no source and no oracle, so a citation carrying one is a
- defect and not a feature arriving early;
+ - zero, or exactly one of the rite's own well-formed shapes,
+ never a partial one -- an Epistle without a Gospel, or the
+ reverse, is a malformed Mass regardless of which shapes the
+ rite declares;
+ - no part outside the rite's own {!Rite.t.citation_shapes} ever
+ appears -- for EF that is still only [First]/[Gospel] (the
+ other chants remain deliberately unbuilt there, with no
+ source and no oracle, so one appearing is a defect, not a
+ feature arriving early); for the OF it is [First]/[Second]/
+ [Gospel], [Second] only ever alongside both of the others (its
+ own doc comment has the full citation and argument);
- no part appears twice -- two Epistles and no Gospel has length
two and would slip past a bare cardinality test.
- [Citation.part]'s own constructor order puts [First] before
- [Gospel], so the sorted well-formed list is literally
- [[First; Gospel]] and nothing else. *)
+ Each of [rite.Rite.citation_shapes]'s own shapes is normalised
+ with the SAME [List.sort compare] a day's actual parts are put
+ through, so a rite may list them in any order without silently
+ failing to match -- robustness the single hardcoded
+ [[First; Gospel]] this replaced never needed to worry about. *)
+ let citation_shapes = List.map (List.sort compare) rite.Rite.citation_shapes in
let year_has_citations =
Array.exists
(fun (d : ('s, 'r) Liturgical_day.t) -> d.Liturgical_day.citations <> [])
@@ -439,7 +447,6 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
List.map (fun (c : Citation.t) -> c.Citation.part) d.Liturgical_day.citations
in
match List.sort compare parts with
- | [ Citation.First; Citation.Gospel ] -> ()
| [] ->
(* Separate check name from the malformed case below on
purpose: this is the lectionary chain falling through
@@ -449,9 +456,11 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
fail date "citations-unresolved"
"no reading citations resolved for this day: the lectionary chain fell through \
every step"
+ | sorted when List.mem sorted citation_shapes -> ()
| sorted ->
fail date "citations"
- (Printf.sprintf "expected exactly one First and one Gospel, got [%s]"
+ (Printf.sprintf
+ "citation parts [%s] match none of this rite's own well-formed shapes"
(String.concat "," (List.map Citation.part_to_string sorted))))
resolved;
(* ---- Formulary invariant (Task 3, celebrant-rubrics-phase1) ----
diff --git a/lib/kernel/validate.mli b/lib/kernel/validate.mli
index 385e111..9ad6b59 100644
--- a/lib/kernel/validate.mli
+++ b/lib/kernel/validate.mli
@@ -84,14 +84,20 @@ val failure_to_string : failure -> string
{!Rite.readings} on every day and is held to neither, so this stays a
check on rites that HAVE readings rather than a demand that every rite
have them.
- - ["citations"]: well-formedness. A day's citation parts, sorted, are
- exactly [[First; Gospel]]. This single condition carries three
- invariants at once: zero or two but never one (an Epistle without a
- Gospel, or the reverse, is a malformed Mass rather than a partial one);
- no part outside [First]/[Gospel] (the chants -- Psalm, Second, Tract,
- Alleluia, Sequence -- are deliberately unbuilt, so one appearing is a
- defect, not a feature arriving early); and no part twice (two Epistles
- and no Gospel has length two and would pass a bare cardinality test).
+ - ["citations"]: well-formedness. A day's citation parts, sorted, must be
+ either empty or equal ONE of [rite.Rite.citation_shapes] exactly --
+ rite-supplied ({!Rite.t.citation_shapes}'s own doc comment has the
+ full citation and argument for why: EF has one shape, [[First;
+ Gospel]]; the OF has two, that same pair plus [[First; Second;
+ Gospel]] on Sundays/solemnities). This single condition carries three
+ invariants at once: zero, or exactly one of the rite's own complete
+ shapes, never a partial one (an Epistle without a Gospel, or the
+ reverse, is a malformed Mass under any rite's shape list); no part
+ outside what the rite itself declares (EF: the other chants remain
+ deliberately unbuilt, so one appearing is a defect, not a feature
+ arriving early); and no part twice (two Epistles and no Gospel has
+ length two and would pass a bare cardinality test, but matches none of
+ a rite's own declared shapes).
- ["citations-unresolved"]: coverage. A day resolved NO citations at all,
i.e. the rite's own lookup chain fell through every one of its steps.
Deliberately a separate label from ["citations"] above: a coverage gap
diff --git a/lib/rites/rite_ef/rite_ef.ml b/lib/rites/rite_ef/rite_ef.ml
index 808e017..8efcbfd 100644
--- a/lib/rites/rite_ef/rite_ef.ml
+++ b/lib/rites/rite_ef/rite_ef.ml
@@ -51,6 +51,13 @@ let context ~lectionary ~commons : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
season_runs = Vocab_ef.seasons;
transfer_target = Precedence_ef.transfer_target;
readings = Lectionary_ef.readings ~lectionary ~commons;
+ (* The one shape the EF Mass has ever had: an Epistle and a Gospel,
+ nothing else (RG carries no Second-reading or responsorial-psalm
+ structure -- that is an OF/OLM 1981 innovation, {!Rite.t
+ .citation_shapes}'s own doc comment has the citation). Kept as the
+ single-element list it always implicitly was before this field
+ existed, so EF's resolved output is unaffected letter for letter. *)
+ citation_shapes = [ [ Citation.First; Citation.Gospel ] ];
creed = Rubrics_ef.creed;
gloria = Rubrics_ef.gloria;
preface = Rubrics_ef.preface }
diff --git a/lib/rites/rite_ef/rite_ef.mli b/lib/rites/rite_ef/rite_ef.mli
index 2ed61de..304bcb6 100644
--- a/lib/rites/rite_ef/rite_ef.mli
+++ b/lib/rites/rite_ef/rite_ef.mli
@@ -33,6 +33,11 @@ module Rubrics_ef = Rubrics_ef
slug, else (a weekday with no entry of its own) the preceding Sunday's
temporal slug, in data/ef/lectionary.sexp. See {!Lectionary_ef.readings}
for why the Common is consulted second rather than last.
+ - [citation_shapes]: the single [[First; Gospel]] shape the EF Mass has
+ always had -- see {!Colitur_kernel.Rite.t.citation_shapes}'s own doc
+ comment for why this is now rite-supplied (the OF needs a second
+ shape) rather than a kernel constant, and this file's own [context]
+ for why EF's own resolved output is unaffected letter for letter.
- [creed]: {!Rubrics_ef.creed}, RG 475-476 -- whether the Creed is said.
The first rubric in this phase governing a part of Mass rather than
occurrence/precedence.
diff --git a/lib/rites/rite_of/rite_of.ml b/lib/rites/rite_of/rite_of.ml
index 9eeb5ef..f45bf50 100644
--- a/lib/rites/rite_of/rite_of.ml
+++ b/lib/rites/rite_of/rite_of.ml
@@ -80,6 +80,19 @@ let context ~lectionary : (Vocab_of.season, Vocab_of.rank) Rite.t =
season_runs = Vocab_of.[ Advent; Christmas; Ordinary_time; Lent; Easter; Ordinary_time ];
transfer_target = Precedence_of.transfer_target;
readings = Lectionary_of.readings ~lectionary ~year_start:Temporal_of.year_start;
+ (* Two well-formed shapes, not EF's one -- OLM 1981 Praenotanda n. 66.1
+ ("Quaelibet Missa tres exhibet lectiones": Sunday/solemnity Mass,
+ First from the OT, Second "ex Apostolo", Gospel) against n. 69.1
+ ("Quaelibet Missa duas exhibet lectiones": ferial Mass, First and
+ Gospel only), both page-image verified,
+ docs/research/of/olm-1981.pdf pp.32-33/"XXXII-XXXIII"; n. 84(b)/(c),
+ pp.37-38/"XXXVII-XXXVIII", extends the three-reading shape to every
+ solemnity of a particular calendar and confines feasts/memorials to
+ two. {!Rite.t.citation_shapes}'s own doc comment has the fuller
+ argument for why this is a rite-supplied field rather than a kernel
+ constant. *)
+ citation_shapes =
+ [ [ Citation.First; Citation.Gospel ]; [ Citation.First; Citation.Second; Citation.Gospel ] ];
creed = Rubrics_of.creed;
gloria = Rubrics_of.gloria;
preface = Rubrics_of.preface }
diff --git a/lib/rites/rite_of/rite_of.mli b/lib/rites/rite_of/rite_of.mli
index eeb38d5..8124467 100644
--- a/lib/rites/rite_of/rite_of.mli
+++ b/lib/rites/rite_of/rite_of.mli
@@ -43,6 +43,13 @@ module Lectionary_of = Lectionary_of
reading-cycle arithmetic's own Advent anchor) -- no [~commons]
parameter, unlike EF: the OF lectionary chain has no Commons
indirection to thread through.
+ - [citation_shapes]: TWO well-formed shapes, not EF's one --
+ [[First; Gospel]] on a feria, feast or memorial, and
+ [[First; Second; Gospel]] on a Sunday or solemnity (OLM 1981
+ Praenotanda n. 66.1/n. 69.1, n. 84(b)/(c)) -- see this file's own
+ [context] for the full citation and
+ {!Colitur_kernel.Rite.t.citation_shapes}'s own doc comment for why
+ this field is rite-supplied at all.
- [creed], [gloria], [preface]: {!Rubrics_of}, IGMR n. 53/67-68/364-365.
[~lectionary] is a caller-supplied parameter, not a value closed over an
diff --git a/test/test_calendar.ml b/test/test_calendar.ml
index 9059574..0b8d3f7 100644
--- a/test/test_calendar.ml
+++ b/test/test_calendar.ml
@@ -122,7 +122,16 @@ module Fixture = struct
(* Not a Roman rite either, so no bissextile-doubling convention:
identity, {!Rite.t.fixed_key}'s own documented default. *)
fixed_key = (fun d -> Some (D.month d, D.day d));
- rules; season_runs = [ A; B ]; transfer_target; readings; creed; gloria; preface }
+ rules; season_runs = [ A; B ]; transfer_target; readings;
+ (* [readings] above is a harmless constant [(None, [])] -- this
+ fixture never actually exercises {!Colitur_kernel.Validate}'s
+ citation checks (it drives {!Colitur_kernel.Calendar.year}
+ directly), so any non-empty shape list satisfies {!Rite.t}'s
+ type without being meaningfully tested here. Mirrors EF's own
+ one-shape [[First; Gospel]] rather than inventing a bespoke
+ synthetic vocabulary for a field this file never reads. *)
+ citation_shapes = [ [ Colitur_kernel.Citation.First; Colitur_kernel.Citation.Gospel ] ];
+ creed; gloria; preface }
let entry ~month ~day ~slug ~rank =
{ Layer.date = (match Date_spec.fixed ~month ~day with Ok d -> d | Error e -> failwith e);
diff --git a/test/test_citation_coverage_of.ml b/test/test_citation_coverage_of.ml
index 70e63ad..7badd96 100644
--- a/test/test_citation_coverage_of.ml
+++ b/test/test_citation_coverage_of.ml
@@ -27,9 +27,20 @@
and {!Colitur_citation.Render}'s own consumption of it), deliberately
not built this task.
+ UPDATED, fix wave I7 (final-review.md, 2026-08-25-colitur-of-phases-3-5,
+ 2026-08-26): {!Rite.t.citation_shapes} (kernel change) plus
+ tools/bootstrap_lectionary_of.ml's own [cite] now also extract a Second
+ reading on every Sunday-cycle (Sunday/solemnity) entry, so the total grew
+ 1542 -> 1725 (+183, exactly the count data/of/lectionary.sexp's own
+ header COVERAGE (5) now discloses) and the unparseable residual grew
+ 41 -> 49: the same chapter-crossing shape, now also hit by 8 of the 183
+ new Second-reading references. Not a new failure MODE, just a bigger
+ population drawing from the same, already-understood one -- confirmed
+ below by [looks_chapter_crossing], unchanged, still holding for all 49.
+
This file pins that residual EXACTLY -- not merely "at least these fail"
-- so it fails loudly in BOTH directions: a NEW unconverted reference
- appearing (a regression) and one of these 41 starting to convert (this
+ appearing (a regression) and one of these 49 starting to convert (this
list going stale, e.g. because a future task builds cross-chapter
support) are both caught, the same discipline every allow-list in this
project's suite already follows (`expected_rows`, `expected_bands`, the
@@ -48,12 +59,14 @@ let lectionary () =
can never silently drift apart without one of them visibly failing to
regenerate/re-test clean. *)
let known_cross_chapter_residual =
- [ "1 Corinthians 12:31-13:13"; "1 John 1:5-2:2"; "1 John 2:29-3:6"; "1 John 3:22-4:6";
- "1 John 4:19-5:4"; "2 Corinthians 3:15-4:1,3-6"; "2 Samuel 18:9-10,14b,24-25a,30-19:3";
- "Colossians 1:24-2:3"; "Ecclesiastes 11:9-12:8"; "Ephesians 4:32-5:8"; "Exodus 11:10-12:14";
- "Exodus 14:21-15:1"; "Ezekiel 2:8-3:4"; "Galatians 4:22-24,26-27,31-5:1"; "Genesis 1:1-2:2";
- "Genesis 1:20-2:4a"; "Habakkuk 1:12-2:4"; "Hebrews 7:25-8:6"; "Isaiah 52:13-53:12";
- "Isaiah 8:23b-9:3"; "John 15:26-16:4a"; "John 18:1-19:42"; "Jonah 1:1-2:2,11"; "Luke 7:36-8:3";
+ [ "1 Corinthians 10:31-11:1"; "1 Corinthians 12:31-13:13"; "1 John 1:5-2:2"; "1 John 2:29-3:6";
+ "1 John 3:22-4:6"; "1 John 4:19-5:4"; "1 Thessalonians 3:12-4:2"; "2 Corinthians 3:15-4:1,3-6";
+ "2 Corinthians 4:13-5:1"; "2 Samuel 18:9-10,14b,24-25a,30-19:3"; "2 Thessalonians 1:11-2:2";
+ "2 Thessalonians 2:16-3:5"; "2 Timothy 3:14-4:2"; "Colossians 1:24-2:3"; "Ecclesiastes 11:9-12:8";
+ "Ephesians 4:30-5:2"; "Ephesians 4:32-5:8"; "Exodus 11:10-12:14"; "Exodus 14:21-15:1";
+ "Ezekiel 2:8-3:4"; "Galatians 4:22-24,26-27,31-5:1"; "Genesis 1:1-2:2"; "Genesis 1:20-2:4a";
+ "Habakkuk 1:12-2:4"; "Hebrews 7:25-8:6"; "Isaiah 52:13-53:12"; "Isaiah 8:23b-9:3";
+ "James 3:16-4:3"; "John 15:26-16:4a"; "John 18:1-19:42"; "Jonah 1:1-2:2,11"; "Luke 7:36-8:3";
"Malachi 1:14b-2:2b,8-10"; "Mark 2:23-3:6"; "Mark 8:34-9:1"; "Matthew 10:34-11:1";
"Matthew 18:21-19:1"; "Matthew 9:35-10:1,5a,6-8"; "Matthew 9:36-10:8";
"Numbers 13:1-2,25-14:1,26a-29a,34-35"; "Philippians 3:17-4:1"; "Revelation 20:1-4,11-21:2";
@@ -91,9 +104,9 @@ let test_of_citations_convert_or_are_the_known_cross_chapter_residual () =
cits)
(Colitur_kernel.Lectionary.entries (lectionary ()));
let bad = List.sort compare !bad in
- Alcotest.(check int) "1542 citation fields in data/of/lectionary.sexp today -- if this changes, the \
+ Alcotest.(check int) "1725 citation fields in data/of/lectionary.sexp today -- if this changes, the \
pinned residual below may need updating too, not just this count"
- 1542 !total;
+ 1725 !total;
Alcotest.(check (list string)) "the unconverted set is EXACTLY the known cross-chapter residual, no \
more and no fewer"
(List.sort compare known_cross_chapter_residual) bad;
diff --git a/test/test_lectionary_of.ml b/test/test_lectionary_of.ml
index 03aaea5..706ee15 100644
--- a/test/test_lectionary_of.ml
+++ b/test/test_lectionary_of.ml
@@ -183,9 +183,17 @@ let test_sha256_pinned () =
the Christmas Day Mass hand-authored from OLM 1981; see
test_coverage_2026's own citation), not header-only as the I2 change
just above was. Re-derived with `sha256sum data/of/lectionary.sexp`,
- same discipline. *)
+ same discipline.
+
+ Fix wave I7 (final-review.md, 2026-08-25-colitur-of-phases-3-5,
+ 2026-08-26): changed again -- {!Colitur_kernel.Rite.t.citation_shapes}
+ (kernel change) plus tools/bootstrap_lectionary_of.ml's own [cite] now
+ also extract a Second reading on every Sunday-cycle entry (183 new
+ citation fields; see data/of/lectionary.sexp's own header COVERAGE (5)
+ and test_citation_coverage_of.ml), and the header's "Epistle" wording
+ is fixed to "First". Re-derived the same way, same discipline. *)
Alcotest.(check string) "data/of/lectionary.sexp SHA-256"
- "e08207614472955974b504bfe6984ff44e882c4d8fadc778c4fa1ddce1adecf8" (sha256_of_file lectionary_path)
+ "0d82069e879d8312943dee543aabc23208265534fcf7edd85c3d9137c2f4581d" (sha256_of_file lectionary_path)
(* lectio's OWN of-lectionary.ini SHA-256, pinned inside data/of/
lectionary.sexp's own provenance header (tools/bootstrap_lectionary_of
diff --git a/test/test_validate.ml b/test/test_validate.ml
index 3da8fbb..4e21829 100644
--- a/test/test_validate.ml
+++ b/test/test_validate.ml
@@ -318,6 +318,23 @@ module Synthetic = struct
[ { Citation.part = Citation.First; reference = "Synth 1:1" };
{ Citation.part = Citation.Gospel; reference = "Synth 2:2" } ]
+ (* A second, OF-shaped well-formed set -- three parts, not two -- so the
+ "more than one declared shape" fixtures below (Task: rite-supplied
+ citation shapes) have real, distinct content to offer, the same
+ "assert SHAPE, never content" discipline [well_formed_citations]
+ above already follows. *)
+ let well_formed_citations_with_second =
+ [ { Citation.part = Citation.First; reference = "Synth 1:1" };
+ { Citation.part = Citation.Second; reference = "Synth 3:3" };
+ { Citation.part = Citation.Gospel; reference = "Synth 2:2" } ]
+
+ (* The default: the one shape every fixture above this point already
+ assumed implicitly, back when [Validate] hardcoded [[First; Gospel]]
+ itself. Overridable ([?citation_shapes] below) for the fixtures that
+ need a rite declaring MORE than one shape, mirroring the real OF's own
+ {!Rite_of.Rite_of.context}. *)
+ let citation_shapes = [ [ Citation.First; Citation.Gospel ] ]
+
(* The formulary equivalent of [well_formed_citations] above -- shape only,
never rubrically meaningful content. *)
let well_formed_formulary =
@@ -335,8 +352,9 @@ module Synthetic = struct
let preface ~temporal:_ ~observed:_ ~date:_ = None
let rite ?(vocab = vocab) ?(anchors = fun _ -> []) ?(season_runs = [ A; B ]) ?(rules = rules)
- ?(transfer_target = fun _ origin _ -> origin) ?(readings = readings) ?(creed = creed)
- ?(gloria = gloria) ?(preface = preface) temporal : (season, rank) Rite.t =
+ ?(transfer_target = fun _ origin _ -> origin) ?(readings = readings)
+ ?(citation_shapes = citation_shapes) ?(creed = creed) ?(gloria = gloria) ?(preface = preface)
+ temporal : (season, rank) Rite.t =
{ Rite.id = "synthetic"; vocab; year_start; temporal; anchors; rules; season_runs;
(* Not a Roman rite, but a Rite.t must supply SOME Easter now that
movable Date_spec variants exist. The Gregorian one is as good as
@@ -346,7 +364,7 @@ module Synthetic = struct
(* Not a Roman rite either, so no bissextile-doubling convention:
identity, {!Rite.t.fixed_key}'s own documented default. *)
fixed_key = (fun d -> Some (D.month d, D.day d));
- transfer_target; readings; creed; gloria; preface }
+ transfer_target; readings; citation_shapes; creed; gloria; preface }
(* Empty by default: every check built before Task 12 exercises the
TEMPORAL-only pass, where an empty layer is exactly the fixture that
@@ -355,10 +373,10 @@ module Synthetic = struct
unchallenged). Task 12's own resolution fixtures pass their own. *)
let empty_layer = Layer.empty ~id:"synthetic-empty" ~name:"empty"
- let run ?vocab ?anchors ?season_runs ?rules ?transfer_target ?readings ?(layer = empty_layer)
- temporal =
+ let run ?vocab ?anchors ?season_runs ?rules ?transfer_target ?readings ?citation_shapes
+ ?(layer = empty_layer) temporal =
Val.run
- (rite ?vocab ?anchors ?season_runs ?rules ?transfer_target ?readings temporal)
+ (rite ?vocab ?anchors ?season_runs ?rules ?transfer_target ?readings ?citation_shapes temporal)
layer ~year:2026
let has_check check (fs : Val.failure list) = List.exists (fun f -> f.Val.check = check) fs
@@ -805,6 +823,43 @@ let test_citations_fires_on_an_out_of_scope_part () =
Alcotest.(check bool) "citations check fires when a part outside First/Gospel appears" true
(has_check "citations" (run ~readings good))
+(* ---- rite-supplied citation shapes (Second-reading kernel change) ----
+
+ [Rite.t.citation_shapes] replaced a single kernel-hardcoded
+ [[First; Gospel]] with a rite-supplied LIST of well-formed shapes -- the
+ OF declares two, EF still only the one. These three fixtures prove the
+ generalisation actually does work, both directions: a multi-shape rite
+ accepts EITHER of its own declared shapes, and a rite that never declared
+ a shape still rejects it even though that exact shape is well-formed for
+ a DIFFERENT (multi-shape) rite -- the check reads the offered rite's own
+ declaration, not a kernel-wide allowance the OF's addition would
+ otherwise silently open up for every rite, EF included. *)
+let multi_shape =
+ [ [ Citation.First; Citation.Gospel ]; [ Citation.First; Citation.Second; Citation.Gospel ] ]
+
+let test_citations_clean_with_a_second_declared_shape () =
+ let readings ~observed:_ ~temporal:_ ~date:_ ~temporal_at:_ =
+ (None, well_formed_citations_with_second)
+ in
+ let fs = run ~readings ~citation_shapes:multi_shape good in
+ Alcotest.(check bool) "a rite that declares [First; Second; Gospel] accepts a day carrying it" false
+ (has_check "citations" fs || has_check "citations-unresolved" fs)
+
+let test_citations_clean_when_a_multi_shape_rite_uses_its_other_shape_too () =
+ let readings ~observed:_ ~temporal:_ ~date:_ ~temporal_at:_ = (None, well_formed_citations) in
+ let fs = run ~readings ~citation_shapes:multi_shape good in
+ Alcotest.(check bool)
+ "the same multi-shape rite also accepts a day carrying only its [First; Gospel] shape" false
+ (has_check "citations" fs || has_check "citations-unresolved" fs)
+
+let test_citations_fires_on_a_shape_the_rite_itself_never_declared () =
+ let readings ~observed:_ ~temporal:_ ~date:_ ~temporal_at:_ =
+ (None, well_formed_citations_with_second)
+ in
+ Alcotest.(check bool)
+ "a rite that never declared [First; Second; Gospel] still flags a day carrying it" true
+ (has_check "citations" (run ~readings good))
+
(* The coverage half, kept a SEPARATE check name from the three above: a rite
that resolves readings on most days but falls through on one. On real EF
data this has no witness at all, so this fixture is the only thing that
@@ -923,6 +978,12 @@ let suite =
test_citations_fires_on_an_out_of_scope_part;
Alcotest.test_case "citations-unresolved fires on a gap" `Quick
test_citations_unresolved_fires_on_a_gap;
+ Alcotest.test_case "citations clean with a second declared shape" `Quick
+ test_citations_clean_with_a_second_declared_shape;
+ Alcotest.test_case "citations clean when a multi-shape rite uses its other shape too" `Quick
+ test_citations_clean_when_a_multi_shape_rite_uses_its_other_shape_too;
+ Alcotest.test_case "citations fires on a shape the rite itself never declared" `Quick
+ test_citations_fires_on_a_shape_the_rite_itself_never_declared;
Alcotest.test_case "formulary silent without a lectionary" `Quick
test_formulary_silent_without_a_lectionary;
Alcotest.test_case "formulary clean when well formed" `Quick
diff --git a/tools/bootstrap_lectionary_of.ml b/tools/bootstrap_lectionary_of.ml
index f94a7db..83019b1 100644
--- a/tools/bootstrap_lectionary_of.ml
+++ b/tools/bootstrap_lectionary_of.ml
@@ -130,25 +130,51 @@ let parse_ini path =
path (List.length other));
List.rev !sections
-(* ---- Citation extraction -- First + Gospel only --------------------- *)
+(* ---- Citation extraction -- First (+ Second on Sundays/solemnities) + Gospel --- *)
-(* Psalm and Second are deliberately dropped, even though lectio's ini
- carries [psalm] (every entry) and [second] (Sundays/solemnities):
- Colitur_kernel.Validate's own ["citations"] check (kernel, off limits to
- this task) hard-asserts every day's citation-part list is EXACTLY
- [[First; Gospel]] -- the identical scope boundary
- tools/bootstrap_lectionary.ml's own [convert] already holds for EF
- ("Nothing here encodes... the chants (Psalm, Second, Tract, Alleluia,
- Sequence) are deliberately unbuilt"). Carrying Psalm/Second through here
- would not add capability today (nothing reads them) and would set up a
- guaranteed collision with that kernel check the moment a future task
- wires Validate over OF data. *)
-let cite sec =
+(* Fix wave I7 (final-review.md, 2026-08-25-colitur-of-phases-3-5): Psalm is
+ still dropped -- it is a CHANT (sung, with a congregational refrain, OLM
+ 1981 Praenotanda n. 71's own "psalmi et versus inter lectiones
+ occurrentes", listed apart from the readings proper), not a reading, and
+ {!Colitur_kernel.Rite.t.citation_shapes} (see that field's own doc
+ comment) still declares no shape carrying it for either rite -- nothing
+ here would read a Psalm citation even if extracted. See the fix wave's
+ own report for the fuller argument and what was rejected.
+
+ Second is now extracted, but ONLY from a SUNDAY-CYCLE section (its own
+ [~is_sunday_cycle] argument, [`A]/[`B]/[`C] at the call site below) --
+ never from a WEEKDAY-CYCLE one ([`I]/[`II]), even on the one occasion
+ lectio's own snapshot carries a stray [second] field there
+ (advent-3-sat-II, "Zephaniah 3:14-17" -- content-verified as a
+ scraping-pipeline artifact, not a real OLM assignment: that citation is
+ the THIRD Sunday of Advent's own Year C first reading, evidently bled
+ into an unrelated Saturday ferial section by niedziela.pl's own
+ generator). This is not merely a guard against that one artifact; it is
+ the general rule OLM 1981 Praenotanda n. 66.1 vs n. 69.1 states (see
+ {!Rite_of.Rite_of.context}'s own citation): a ferial Mass has two
+ readings, never three, so a weekday-cycle section can never legitimately
+ carry a Second reading regardless of what stray data a snapshot exposes.
+ {!Colitur_kernel.Validate}'s own rite-supplied ["citations"] check (no
+ longer off limits to this task -- the kernel change this fix wave itself
+ makes) would reject an emitted weekday-cycle entry carrying [Second]
+ outright, since neither of the OF's two declared shapes admits it
+ alongside a non-Sunday/solemnity office; extracting it here regardless
+ would just move the failure from "silently wrong" to "loudly rejected at
+ test time" rather than avoiding it. *)
+let cite ~is_sunday_cycle sec =
let get k = match List.assoc_opt k sec.fields with None | Some "" -> None | Some v -> Some v in
match (get "first", get "gospel") with
| Some first, Some gospel ->
- Some [ { Citation.part = Citation.First; reference = first };
- { Citation.part = Citation.Gospel; reference = gospel } ]
+ let second =
+ if is_sunday_cycle then
+ Option.map (fun v -> { Citation.part = Citation.Second; reference = v }) (get "second")
+ else None
+ in
+ Some
+ (List.filter_map Fun.id
+ [ Some { Citation.part = Citation.First; reference = first };
+ second;
+ Some { Citation.part = Citation.Gospel; reference = gospel } ])
| _ -> None
(* ---- Cycle-family grouping ------------------------------------------ *)
@@ -216,21 +242,25 @@ let collapse_sunday base va vb vc =
Printf.eprintf
"bootstrap_lectionary_of: %s: cycle C disagreed with A/B (scraping-year \
artifact, majority kept): %s\n"
- base (match vc with [ f; _ ] -> f.Citation.reference | _ -> "?");
+ (* [f :: _], not a fixed-arity [[f; _]]: [cite] now emits either a
+ 2-element ([First; Gospel]) or 3-element ([First; Second; Gospel])
+ list, and [First] is its head either way -- a fixed-arity pattern
+ would silently fall through to "?" on the 3-element shape. *)
+ base (match vc with f :: _ -> f.Citation.reference | [] -> "?");
Flat va
end
else if va = vc then begin
Printf.eprintf
"bootstrap_lectionary_of: %s: cycle B disagreed with A/C (scraping-year \
artifact, majority kept): %s\n"
- base (match vb with [ f; _ ] -> f.Citation.reference | _ -> "?");
+ base (match vb with f :: _ -> f.Citation.reference | [] -> "?");
Flat va
end
else if vb = vc then begin
Printf.eprintf
"bootstrap_lectionary_of: %s: cycle A disagreed with B/C (scraping-year \
artifact, majority kept): %s\n"
- base (match va with [ f; _ ] -> f.Citation.reference | _ -> "?");
+ base (match va with f :: _ -> f.Citation.reference | [] -> "?");
Flat vb
end
else Sunday_cycle (va, vb, vc)
@@ -271,7 +301,8 @@ let resolve_sections secs =
match base_and_letter sec.name with
| None -> die "%s: no recognised cycle suffix (-A/-B/-C/-I/-II)" sec.name
| Some (base, letter) -> (
- match cite sec with
+ let is_sunday_cycle = match letter with `A | `B | `C -> true | `I | `II -> false in
+ match cite ~is_sunday_cycle sec with
| None -> die "%s: no first/gospel field" sec.name
| Some cs ->
let cur = try Hashtbl.find tbl base with Not_found -> (None, None, None, None, None) in
@@ -632,12 +663,18 @@ let slug_or_die name = match Slug.of_string name with Ok s -> s | Error e -> die
the VIGIL, not the Day). Confirmed sourceable, not merely "cannot
convert": docs/research/of/olm-1981-ocr.txt:4513-4520 ("16 Ad Missam in
die"), the same primary authority this whole module already cites for
- the cycle rules (lectionary_of.mli). First reading and Gospel only,
- matching this file's own scope everywhere else (data/of/lectionary.sexp
- :2's own header, and {!Colitur_kernel.Validate}'s [First; Gospel]
- assertion) -- OLM's own Second Reading (Heb 1:1-6) and Psalm (Ps 97) are
- out of scope for the identical reason every other day's Second Reading
- and Psalm are (I7, a kernel-level limitation, not this file's own).
+ the cycle rules (lectionary_of.mli).
+
+ UPDATED, fix wave I7 (final-review.md, 2026-08-25-colitur-of-phases-3-5,
+ 2026-08-26): Christmas Day is a solemnity, so its own Second Reading is
+ now in scope and included -- Hebr 1, 1-6 ("Locutus est nobis Deus in
+ Filio"), same source line (docs/research/of/olm-1981-ocr.txt:4517),
+ confirming the value this comment already named before this fix wave
+ built the capability to emit it. Psalm (Ps 97) remains out of scope,
+ deliberately, not merely by omission -- see [cite]'s own doc comment
+ above for the argument (a chant, not a reading; no declared
+ {!Colitur_kernel.Rite.t.citation_shapes} shape carries it for either
+ rite).
The Gospel (Io 1, 1-18) carries OLM's own "longior/brevior" choice
("1-18 (longior) vel 1-5.9-14 (brevior)") -- the LONGER form is used,
@@ -654,6 +691,7 @@ let slug_or_die name = match Slug.of_string name with Ok s -> s | Error e -> die
let hand_authored =
[ ( slug_or_die "of-nativity",
[ { Citation.part = Citation.First; reference = "Isaiah 52:7-10" };
+ { Citation.part = Citation.Second; reference = "Hebrews 1:1-6" };
{ Citation.part = Citation.Gospel; reference = "John 1:1-18" } ] ) ]
let entries_of (slug, r) =
@@ -910,11 +948,25 @@ let () =
temporal_day_gap ~lectionary:lect ~year_start:Rite_of.Temporal_of.year_start
in
let cit_total, cit_bad = citation_conversion_census lect in
+ (* Fix wave I7 (final-review.md, 2026-08-25-colitur-of-phases-3-5): how
+ many emitted citation FIELDS are a Second reading -- i.e. how many of
+ [entries]'s own Sunday-cycle entries actually carried one in lectio's
+ snapshot (Sunday-cycle sections without a NAMED Second in the ini, and
+ every weekday-cycle entry by [cite]'s own [~is_sunday_cycle] guard,
+ never get one). Printed in the header below alongside [cit_total] so a
+ reader can see the Second-reading count is a real, measured subset of
+ the total, not a guess. *)
+ let second_count =
+ List.concat_map snd entries
+ |> List.filter (fun (c : Citation.t) -> c.Citation.part = Citation.Second)
+ |> List.length
+ in
let oc = open_out dst in
Printf.fprintf oc
"; data/of/lectionary.sexp -- OF (2002) temporal + sanctoral lectionary\n\
- ; (Epistle + Gospel citations, never scripture text), bootstrapped from\n\
- ; lectio.\n\
+ ; (First, and on Sundays/solemnities also Second, and Gospel citations,\n\
+ ; never scripture text -- \"Epistle\" is EF vocabulary, not used here),\n\
+ ; bootstrapped from lectio.\n\
;\n\
; LINEAGE, stated loudly because it constrains what this file can show\n\
; (design spec 2026-08-24-colitur-of-rite-module-design.md sec4.4/sec5):\n\
@@ -962,6 +1014,19 @@ let () =
; three genuinely different structural-unreachability reasons, none of\n\
; them \"duplicate\" -- see [excluded_bases]'s own comment.\n\
;\n\
+ ; CORRECTED, fix wave I7 (final-review.md, 2026-08-25-colitur-of-\n\
+ ; phases-3-5, 2026-08-26): this file used to carry First and Gospel\n\
+ ; only, and called the First reading an \"Epistle\" above -- EF\n\
+ ; vocabulary, wrong for the OF (its First reading is often Old\n\
+ ; Testament or Acts, not an epistle at all; OLM 1981 Praenotanda\n\
+ ; n. 66.1). Both fixed at the source: {!Colitur_kernel.Rite\n\
+ ; .t.citation_shapes} (kernel change, {!Rite_of.Rite_of.context}'s own\n\
+ ; citation) makes the well-formed citation-part shape RITE-supplied\n\
+ ; rather than a kernel-hardcoded [[First; Gospel]], and [cite] above\n\
+ ; now extracts a Second reading from every SUNDAY-CYCLE (Sunday/\n\
+ ; solemnity) entry lectio's own snapshot carries one for. See\n\
+ ; COVERAGE (5) below for the measured count.\n\
+ ;\n\
; Source: %s\n\
; SHA-256: %s\n\
; %d ini sections (988 expected) -> %d resolved (base, cycle-shape) \
@@ -991,7 +1056,7 @@ pairs -> %d colitur slugs mapped, %d ini bases genuinely excluded (structurally\
; OLM norms working as designed for a saint with no proper of\n\
; their own, not a gap in this data.\n\
; (4) Citation-siglum conversion (fix wave I2, 2026-08-26 review): of\n\
- ; %d emitted (First, Gospel) citation fields, %d distinct\n\
+ ; %d emitted (First, Second, Gospel) citation fields, %d distinct\n\
; references (out of the full %d) do not parse -- every one a\n\
; hyphen range that crosses a chapter boundary (\"2:29-3:6\"), a\n\
; {!Colitur_citation.Parse.t} shape this parser's [part]/\n\
@@ -1004,6 +1069,19 @@ pairs -> %d colitur slugs mapped, %d ini bases genuinely excluded (structurally\
; .format}'s own documented contract on a parse miss. Pinned\n\
; exactly, both directions, by test/test_citation_coverage_of.ml.\n\
; Named below.\n\
+ ; (5) Second-reading coverage (fix wave I7, 2026-08-26): %d of the\n\
+ ; %d emitted citation fields above are a Second reading -- every\n\
+ ; one from a SUNDAY-CYCLE (-A/-B/-C, i.e. Sunday/solemnity)\n\
+ ; entry, never a weekday-cycle one ([cite]'s own\n\
+ ; [~is_sunday_cycle] guard), matching OLM 1981 Praenotanda\n\
+ ; n. 66.1/n. 69.1 and n. 84(b)/(c) (docs/research/of/olm-1981\n\
+ ; .pdf pp.32-33,37-38/\"XXXII-XXXIII\",\"XXXVII-XXXVIII\"): a\n\
+ ; Sunday or solemnity Mass has three readings, a feria/feast/\n\
+ ; memorial two. The Responsorial Psalm (lectio's own [psalm]\n\
+ ; field, present on nearly every section) is deliberately NOT\n\
+ ; extracted -- see [cite]'s own doc comment for the argument\n\
+ ; (a chant, not a reading; declared in neither rite's\n\
+ ; {!Colitur_kernel.Rite.t.citation_shapes}).\n\
; Regenerate with:\n\
; eval $(opam env) && dune exec tools/bootstrap_lectionary_of.exe -- %s %s\n"
src (sha256 src) (List.length secs) (List.length resolved) report.mapped
@@ -1011,7 +1089,7 @@ pairs -> %d colitur slugs mapped, %d ini bases genuinely excluded (structurally\
gap_total gap_count (List.length report.unmapped) (List.length resolved)
(Hashtbl.length sanctoral_slugs) report.sanctoral_passthrough
(Hashtbl.length sanctoral_slugs - report.sanctoral_passthrough)
- cit_total (List.length cit_bad) cit_total src dst;
+ cit_total (List.length cit_bad) cit_total second_count cit_total src dst;
Printf.fprintf oc "; Unmapped lectio bases (%d):\n" (List.length report.unmapped);
List.iter (fun b -> Printf.fprintf oc "; %s\n" b) report.unmapped;
Printf.fprintf oc "; Citations that do not parse (%d distinct, all chapter-crossing ranges):\n"