diff options
| -rw-r--r-- | data/of/lectionary.sexp | 228 | ||||
| -rw-r--r-- | lib/kernel/rite.ml | 1 | ||||
| -rw-r--r-- | lib/kernel/rite.mli | 36 | ||||
| -rw-r--r-- | lib/kernel/validate.ml | 31 | ||||
| -rw-r--r-- | lib/kernel/validate.mli | 22 | ||||
| -rw-r--r-- | lib/rites/rite_ef/rite_ef.ml | 7 | ||||
| -rw-r--r-- | lib/rites/rite_ef/rite_ef.mli | 5 | ||||
| -rw-r--r-- | lib/rites/rite_of/rite_of.ml | 13 | ||||
| -rw-r--r-- | lib/rites/rite_of/rite_of.mli | 7 | ||||
| -rw-r--r-- | test/test_calendar.ml | 11 | ||||
| -rw-r--r-- | test/test_citation_coverage_of.ml | 31 | ||||
| -rw-r--r-- | test/test_lectionary_of.ml | 12 | ||||
| -rw-r--r-- | test/test_validate.ml | 73 | ||||
| -rw-r--r-- | tools/bootstrap_lectionary_of.ml | 136 |
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" |
