Audit the Slavic readings and commemorations against oca.org - #225
Open
brianglass wants to merge 20 commits into
Open
Audit the Slavic readings and commemorations against oca.org#225brianglass wants to merge 20 commits into
brianglass wants to merge 20 commits into
Conversation
The Slavic data predates the Greek tradition by years and had never been measured against its own source, the way docs/greek-lectionary.md measured Greek against goarch.org. This is that measurement: 329/339 dates match for 2026, with ten differing in three coherent groups. The largest group is one unmodelled rule rather than four separate mistakes. The app and oca.org disagree about whether the ordinary daily-cycle reading is also read when a feast claims the day, and they disagree in both directions: on Jan 1, Jan 5 and Dec 24 oca.org reads it alongside the festal reading and the app omits it; on Jan 3, a Saturday before a great feast, oca.org drops it and the app adds it. Not fixed here -- the rule is inferred from four dates in one year, and this project confirms across several years before coding. Two traps in oca.org's monthly tables are recorded because both produced confidently wrong numbers. Their columns are not positionally stable: Feb-Apr carry an extra column, and a Lenten day's Old Testament lessons sit in the cells a Liturgy day uses for Epistle and Gospel, so reading slots off column numbers scored the app at 73.7%. And neither side is self-consistent about slots -- oca.org labels Holy Week's Bridegroom gospels "(Matins)" while the app files them under "Gospel" -- so the audit matches on citations and reports missing and extra separately rather than pairing by slot. Also notes that oca.org 403s a user agent containing the word "harvester". That is a keyword filter, not the access policy: robots.txt allows these paths and asks for Crawl-delay: 10, which tools/oca/fetch.py honours. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The audit described oca.org's "(Matins)" and the app's "Gospel" as inconsistent classifications of the same reading. They are not. A reading has a kind and a service, and those are independent: Holy Week's Bridegroom readings are Gospels and are read at Matins. Each source names a different axis and neither is wrong. `Reading.source` is compositional over both, with either omissible -- "Gospel" is a Liturgy Gospel by default, "Vespers" names only the service, "Matins Gospel" names both. Six Holy Week rows carry the service in `desc` instead (Bridegroom, At the Washing of the Feet), which loses a reader nothing but does defeat a matcher keying on `source`. The foot-washing gospels were called a classification issue; they are correct as stored, and were only surfacing because the audit's "extra" direction keys on source. No behaviour change -- the audit already matched on citations rather than slots, and 2026 still scores 329/339. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Verified against the fixture: 320 of 359 Vespers rows (89%) are Old Testament lessons. The exceptions are principled rather than noise -- 38 are Catholic Epistles on apostolic feasts, where the three Old Testament lessons are replaced by three from James, 1 Peter, 1 John or Jude for the apostle being kept, and 1 is a genuine Vespers Gospel with its own source value. That makes `Vespers` effectively self-describing: an Old Testament lesson unless the day is an apostle's feast. Useful in both directions -- an unexplained New Testament reading under `Vespers` on a non-apostolic day would be worth a second look. Adds refs.classify(), which falls back to the book name when a citation has no chapter:verse. 38 Vespers rows are composite lessons displayed as "Composite 2 - Proverbs 10, 3, 8" -- canon() cannot tokenise those, so they were unclassified. They can now be classified even though they can never be matched by citation; all 38 are Old Testament. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The marker is invisible and undocumented, and its author no longer remembered why it was there. Git history has it: e5fb471 (Nov 2023) hardcoded `not in ('17', '18')` here with the comment "for some reason we are missing composites 17 and 18"; d4d5d54, ten minutes later, moved that special case out of the code and into the data as a U+200B. "Tomorrow" in that commit message was Nov 21 -- the Entrance of the Theotokos, the feast these two serve. The reason they are missing is now established. They are the Slavic propers for that feast, Exodus 40 and 3 Kingdoms 7-8. Our composite text is Archimandrite Ephrem Lash's Prophetologion (~/src/anastasis), and his book assigns the Greek Marian set to the Entrance instead -- Genesis 28, Ezekiel 43, Proverbs 9. Those two readings are simply not in it. Only the Ezekiel overlaps, which is why it alone is already a plain reference. Also corrects this function's own comment, which described the Composite content column as KJV-sourced. It is not; the register is plainly Ephrem's. Records that the marker is a stopgap rather than a design. Approximating a composite with a reference works here only because these two have exact verse ranges. Composite 24 is Leviticus 26:3-12, 14-17, 19-20, 22, 33, 23-25 -- verse 33 before 23-25 -- which no reference can express, and is why the table exists at all. Comment only; 189 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The previous comment claimed Composite 24's "Leviticus 26:3-12, 14-17, 19-20, 22, 33, 23-25" could not be expressed as a reference because verse 33 precedes 23-25. That is wrong. bible.models.lookup_reference splits on the separators and ORs the ranges, and the segment order survives into the result: it renders that reference with 33 ahead of 23-25 as written, and Composite 20's "Isaiah 55:1; 12:3-4; 55:2-13" with the chapter jumping backwards and forwards. Production already depends on this for the Holy Thursday composite gospel, which is a five-segment cross-book reference. Worth knowing that the ordering follows the OR terms in the generated query rather than an explicit order_by; there is no Meta.ordering on Verse. The real reason a composite is not replaceable by a reference is the text, not the verse selection. The stored text is Archimandrite Ephrem Lash's from the LXX while the Verse table's Old Testament is KJV and Masoretic -- "If you walk in my ordinances" against "If ye walk in my statutes" -- and it carries the liturgical incipit, which is not scripture: Composite 24 opens "The Lord spoke to the children of Israel saying", which is nowhere in Leviticus 26:3. Comment only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Its sdisplay was "Lev 26", which resolves to all 46 verses of the chapter where the reading is a 21-verse selection. Anastasis spells it out in full -- Leviticus 26:3-12, 14-17, 19-20, 22, 33, 23-25 -- so sdisplay now carries that. Inert today, since the pericope routes through the Composite table, but it was wrong and it is the kind of wrong that only shows up later. Eight other composites remain chapter-only for a reason that is worth recording: Ephrem did not enumerate them. His specifications read "Proverbs 10:31-32 & Selection", "40:1 and selection", "3 & 4 and selection". There is no verse list to recover, so the stored text is itself the specification. Composite 24 was the only one written out in full. Measured LXX2012-WEB against the composite text while checking whether references could replace composites: mean word-level similarity to Ephrem is 58%, against 46% for KJV, and LXX2012 is closer on 12 of 13 composites that have both a precise spec and stored text. Both descend from the Septuagint, so that is the expected direction, and it makes LXX2012 the right base if any conversion is ever attempted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Composite 17 and 18 have no Ephrem text -- they are the Slavic propers for the
Entrance of the Theotokos and are absent from his Prophetologion -- so they are
approximated by a scripture reference. Reading oca.org's text for them
alongside ours shows 17 is right verse for verse and 18 is not.
18 was "3 Kgs 7:51-8:1, 8:4-7, 9-11", which both includes a verse oca.org does
not have and omits one it does:
7:51 "So the work of the house of the Lord ... was finished; and Solomon
brought in the holy things of David his father" -- absent from oca.org's
text, which opens at 8:1.
8:3 "And the priests took up the ark" -- present in oca.org's first part,
and skipped by the old range, which jumped 8:1 -> 8:4.
Corrected to "3 Kgs 8:1, 3-7, 9-11". Word-level similarity to oca.org's text
goes from 41% to 73% in LXX2012, and the expected ordering is restored --
LXX2012 ahead of KJV (73% against 62%), matching Composite 17's 69% and the
58%-vs-46% pattern across every other composite. The old range was the one
place LXX2012 scored *below* KJV, which is what drew attention to it.
Both display and sdisplay updated; the zero-width space on display is intact.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Six of the eight chapter-level composite references are replaced with the actual verse selections. They were things like "Isa 40, 41, 45, 48, 54", which resolves to 123 verses where the reading is ten. Nobody publishes these selections. Ephrem writes "and selection"; oca.org titles a composite by chapter and numbers its parts rather than its verses, where an ordinary reading gets true verse numbers; orthodox_calendar stores opaque part keys. The text is the only record of what a composite contains. oca.org publishes the same composite corpus under the same numbering -- verified word-for-word identical to orthodox_calendar on Composites 17 and 18, 181 and 209 words with no differences -- so its text is good evidence of which verses are covered, even though the translation is not Ephrem's and cannot replace ours. Each composite was read against our Bible by eye rather than matched by threshold: Composite 18's error was found by reading, and no threshold would have flagged it. Fidelity, as word-level similarity between oca.org's text and our LXX2012-WEB rendering, against the 59-78% band set by the sixteen specs that were already precise: 13 3 Kgs 18, 19 62% -> 74% 8 Isaiah 11% -> 66% 2 Proverbs 17% -> 64% 3 Wisdom 24% -> 56% 9 Malachi 34% -> 54% 6 Exod/Lev/Num 15% -> 53% Composites 4 and 5 are left loose. Their derived specs score 44% and 37%, and that is not a failure to find the right verses -- adding candidates made them worse -- but free adaptation that no reference can represent. sdisplay is published as the API's short_display, so a low-confidence guess there would present inference as fact; Composite 5's spec also exceeds the column's max_length of 64. That API exposure is why calendarium/tests/data/january.json changes: the Composite 2 reading falls on January 25 and 27. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The point of deriving the verse selections was to see whether composites could
become plain references resolved in the reader's own translation. They cannot:
only three of eight derivations reach the 59-78% band that the already-precise
specs occupy, and Composites 4 and 5 get *worse* as candidate verses are added,
because they are free adaptations rather than selections. A partial conversion
would render some composites in the reader's translation and others in
Ephrem's, on the same page, for no gain in what the reader sees.
So the mechanism stays as it was: Ephrem's text for the 22 that have it, and
the zero-width-space fall-through for 17 and 18. The six derived specs that had
been written into the fixture are reverted, and the research is kept in
docs/oca-audit.md where it belongs.
Reverting them matters because sdisplay is not a private note. calendarium/api.py
publishes it as the API's short_display, documented as "the scripture reference
with abbreviated book name" -- a test failure on calendarium/tests/data/january.json
is what surfaced that. For a composite there is no such reference, the loose
form is what oca.org itself prints as the title, and an enumerated guess there
would assert a precision measured at 53-64%.
Two corrections do remain, because neither is inference:
Composite 18 "3 Kgs 7:51-8:1, 8:4-7, 9-11" -> "3 Kgs 8:1, 3-7, 9-11".
The old range carried 7:51, which oca.org's text does not have,
and skipped 8:3, which it does. This one is functional: 18 is a
fall-through, so the range is what readers actually get.
Composite 24 "Lev 26" -> "Lev 26:3-12, 14-17, 19-20, 22, 33, 23-25", the
whole 46-verse chapter against a 21-verse reading. Ephrem
spells this one out, so the spec is his, not derived.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The first actual fix from the Slavic audit rather than a measurement. Oct 31 was the only date differing in all five harvested years (2023-2027), which is what drew attention to it -- it had been filed as a one-off. oca.org gives St John Kochurov a proper Gospel and no proper Epistle: the Epistle is the ordinary daily one, and it differs every year (Col 2:20-3:3, Phil 1:20-27, Col 2:1-7, 2 Cor 5:1-10, 2 Cor 11:31-12:9), which is what proves it is the daily reading rather than a proper. The Gospel is John 10:9-16 in all five years, labelled for him. The app had a proper Epistle, Hebrews 13:7-16, and gave him Luke 12:32-40. Both are plausible hieromartyr commons, which is presumably where they came from, but oca.org is the source this data was compiled from and it disagrees consistently. - Gospel repointed from Luke 12.32-40 to John 10.9-16. - The Hebrews 13:7-16 Epistle row is removed; reading rows 1807 -> 1806. Oct 31 now differs by one citation a year instead of three. What remains is the app keeping the ordinary daily Gospel where oca.org replaces it -- the same replace-versus-append question as Jan 1, Jan 5 and Dec 24, and not a fact about this date. Note when checking locally that loaddata is additive: it will not remove the deleted row from an existing dev database, and the audit still reported HEB13:7 until it was deleted explicitly. Production rebuilds the database from the fixture at image build, so it is unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Harvesting 2023-2027 corrected two conclusions drawn from 2026 alone: Oct 31 is not a one-off but the only date differing in all five years, and Jan 3 is not a fixed-date problem but the Saturday before Theophany moving across Jan 2-4. One year is enough to find a candidate and not enough to rank it. Records why the remaining rule -- whether the ordinary daily reading coexists with a proper one -- is not being implemented yet. The harness cannot prove such a change safe: aget_readings is on the base Day class shared by SlavicDay and GreekDay, so a change made for Slavic accuracy is measured for Greek against a different source and could cost the 99.1% silently; and both audits check the Liturgy Epistle and Gospel only, 894 of 1,446 readings a year, leaving 38% unmeasured on precisely the feast days the rule governs. The prerequisite is extending the audit to /readings/daily/, which lists every service. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Acting on the harvested oca.org commemorations: 365 dates, 2,968 entries from /saints/lives/. A DayCommemoration tagged `greek` asserts the Slavic tradition does not keep it, so Slavic users were not shown these at all. Screening the 730 greek-tagged commemorations against oca.org for the same date turned up 99 candidates at full token overlap. The unambiguous ones share a Slavic or Balkan place marker, which makes a greek-only tag self-evidently wrong -- three are Kiev Caves saints: 01-02 Sylvester of the Kiev Caves | Venerable Sylvester of the Kiev Near Caves 01-04 Eustathios Archbishop of Serbia | Repose of St Eustathius I, Archbishop of Serbia 01-08 Gregory of the Kiev Caves | Venerable Gregory, Wonderworker of the Kiev Near Caves 04-08 Rufus the Obedient, Kiev Caves | Venerable Rufus the Obedient of the Kiev Far Caves 05-22 John-Vladimir, Ruler of Serbia | St John-Vladimir, Prince of Bulgaria, Greatmartyr 07-27 Nicholas of Novgorod, fool-for-Christ | Blessed Nicholas Kochanov the Fool-For-Christ at Novgorod 08-28 Synaxis of the Kiev Cave Fathers | Synaxis of the Saints of the Kiev Caves 11-27 James the Wonderworker of Rostov | St James the Wonderworker, Bishop of Rostov 12-13 Gabriel, Archbishop of Serbia | Hieromartyr Gabriel of Serbia Each was checked against the full oca.org listing for its date rather than trusting the score. Retagged common; all nine now appear for both traditions. The remaining ~90 candidates are NOT retagged. Name overlap alone is not evidence, and the standing trap on this project is that a same-name match is usually noise: Sept 24 pairs our "Stephen the Martyr" with oca.org's "Holy King Stephen of Serbia", who is a different person, and Catherine of Alexandria is genuinely Nov 24 for Slavic and Nov 25 for Greek, a distinction that must not be collapsed. Those need reading one at a time. calendarium/tests/data/january.json is regenerated because Jan 2, 4 and 8 now carry three more saints for the default tradition. Regenerate it with indent=4, ensure_ascii=False and no trailing newline, or the diff is 2,300 lines of reformatting instead of three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The evidence behind the composite verse selections in docs/oca-audit.md: all 24 composites as oca.org publishes them, harvested by tools/oca/harvest_composites.py. Kept in the repo so the readings can be re-checked without another hour of crawling, and because oca.org is the only source that prints these texts in a form a machine can read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Completes the read-through begun in the previous commit. Every one of the 93
remaining candidates was read as a pair of titles and judged individually;
`greek` went from 730 commemorations to 630.
Two were rejected as different people sharing a name and a date, which is the
failure mode this whole exercise had to guard against:
08-30 ours "The Holy New Martyrs of Serbia" against oca.org's "Saint
Spyridon, Patriarch of Serbia". oca.org's Aug 30 has the Synaxis of
the Serbian Hierarchs and three individual patriarchs, and no
commemoration of the new martyrs at all.
09-24 ours "Stephen the Martyr" against oca.org's "Holy King Stephen of
Serbia" -- a king, not a martyr, and not the same man.
Seven more looked thin because our title is generic -- "Stephen the Monk",
"Julian the Martyr", "Serapion the Martyr", "Phaedrus the Martyr". Each was
checked against the whole day's listing rather than the score, and in every
case exactly one entry out of seven to eleven carries that name, which settles
it: a rare name kept on the same date is the same saint.
Several of the accepted ones are plainly Slavic and were never Greek-only:
Nilus of Sora, Theodosius of Totma in Vologda, Moses the Hungarian of the Kiev
Near Caves, the 26 Martyrs in the Crimea.
calendarium/tests/data/january.json is regenerated again; Jan 4, 5, 10 and 28
gain saints, and Jan 10 and Jan 28 gain them in summary_title as well.
What remains greek-tagged is now dominated by Ottoman-era Greek New Martyrs and
Athonite figures, which is what that tag should mean. Nothing below full token
overlap has been reviewed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
f4279e0 removed St John Kochurov's Hebrews 13:7-16 and repointed his Luke 12:32-40 to John 10:9-16, on the grounds that oca.org's monthly lectionary showed only "2 Corinthians 5:1-10 / John 10:9-16 (St. John Kochurov)" in all five harvested years. The all-services harvest shows that was wrong. oca.org's daily page for the same date lists five readings: Hebrews 13:7-16 (Epistle, St. John Kochurov) Luke 12:32-40 (Gospel, St. John Kochurov) John 10:9-16 (Gospel, St. John Kochurov) 2 Corinthians 5:1-10 (Epistle) Luke 8:16-21 (Gospel) The app's data was right except for one omission. Both readings are restored and John 10:9-16 is added as the reading that was genuinely missing. Oct 31 now matches oca.org exactly, where the previous "fix" left it differing by two. The monthly lectionary is not merely Liturgy-only, which tools/oca/harvest_readings.py already documents. It is *lossy*: it drops Epistle and Gospel readings the daily page carries, keeping one reading set per label. Two of the three readings it omitted here are labelled Epistle and Gospel by oca.org itself, so no rule about services would have predicted it. Prefer /readings/daily/ for anything that will change data. This is the failure the coverage note in docs/oca-audit.md predicted in the abstract -- a change that looked right against 38%-coverage evidence and was wrong against the whole day -- arriving before the logic change it was written about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Closes the 38% coverage gap that the previous note called a prerequisite. harvest_daily.py pulls /readings/daily/, which lists every service -- Theophany Eve returns 34 readings there against the monthly lectionary's two -- and audit_daily.py compares the whole day on both sides, symmetrically, since neither side is now truncated. Baseline 352/365 dates matching exactly, 1,448 app readings against 1,438. The previously unmeasured 38% is almost entirely clean: Theophany Eve's thirteen Vespers lessons, four sets of Hours and Blessing of Waters all match, and the day differs only in the two Liturgy readings already known about. canon() now recognises composites by number. Both sides name them "Composite N", but oca.org prints no verses, so the citation was unparseable and the app's resolved reference looked spurious -- Nov 21 was a false difference. classify() falls through to the book name for those tokens so the Vespers OT classification still holds. New findings the Liturgy-only audit could not see, chiefly a one-day offset: Composites 2, 3 and 4 fall on Mar 30 here and Mar 31 on oca.org. That is a wrong date rather than a wrong reading, and the two halves cancel out in any per-year total. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Brian noticed on Aug 29 that the Beheading of the Forerunner's Epistle and Gospel sort after the ordinary weekday readings, so the abbreviated readings -- what the Alexa skill speaks -- never reach them. It generalises to every feast at level 6. `ordering` runs in tiers: 801/901 sorts a reading before the daily cycle at 811/911, and 821/921 after it. Levels 7 and 8, the Twelve Great Feasts, all use tier 0 already. Level 6 is "red cross circle (great feast typikon symbol)" -- the Typikon's highest rank below those -- and every one of its six fixed dates was at tier 2. aget_abbreviated_readings takes the first Epistle and the first Gospel after it, so on four of the six the skill was reading the ordinary weekday lesson and never naming the feast: 06-24 Nativity of the Forerunner Romans 11.2-12 / Matthew 11.20-26 06-29 Peter and Paul Romans 12.4-5,15-21 / Matthew 12.9-13 08-29 Beheading of the Forerunner 1 Cor 2.6-9 / Matthew 22.15-22 11-16 Apostle and Evangelist Matthew 2 Thess 1.1-10 / Luke 14.12-15 Peter and Paul is the starkest. Jan 1 was already correct, but only by accident: the app has no daily reading on Circumcision, so the feast's won by default. That gap is itself a known difference against oca.org, and closing it would have broken Jan 1 -- so it is retiered too, along with St Basil to 802/902 behind it, which is the order oca.org prints. 16 rows moved from 821/921 to 801/901 (822/922 -> 802/902 for St Basil). No reading is added or removed; the sets are identical and only the order changes. Verified: all five feasts now speak their own readings, the all-services audit holds at 352/365, and Greek against goarch.org holds at 333/336. calendarium/tests/data/january.json changes accordingly: abbreviated_reading_indices on Jan 1 move from [5, 8] to [4, 7], and the day's readings now run Circumcision, St Basil, Saturday before Theophany. Level 5, the vigil rank, is deliberately untouched -- eleven more dates, including St Nicholas and John Chrysostom, where the same argument could be made but the Typikon draws a distinction. That is a judgement call for Brian, not a bug. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
aget_abbreviated_readings took the first Epistle and the first Gospel after it, by `ordering`. That made the Alexa skill read the ordinary weekday lesson on feast days -- Peter and Paul, the Beheading, the Three Hierarchs -- and it had never been measured, because there was no obvious ground truth for "the" reading of a day. There are three. antiochian.org and goarch.org each publish exactly one pair a day and agree with each other on every feast checked. oca.org's monthly lectionary lists sets per date, propers labelled -- useful, but its row order is not reliably primary-first: Jan 1 leads with Circumcision while Feb 2, the Meeting of the Lord, leads with the daily reading. That ruled out the simplest approach of trusting the first row. Measured against antiochian.org for 2026, on days having a proper, the proper wins from about feast level 3 upward and the daily wins below it. Splitting level 3+ by weekday sharpens it: proper 59 to 8 on weekdays, daily 7 to 1 on Sundays, the resurrectional reading taking precedence over almost any saint. **That Sunday split is why the rule is code and not data.** Whether a fixed date falls on a Sunday changes from year to year, while `ordering` is static, so retiering rows could never express it. Implemented as: prefer the day's propers when feast_level >= 3 and the day is not a Sunday, otherwise prefer the ordinary readings, falling back to whatever exists. Lenten weekdays pass through untouched -- there is no Epistle/Gospel pair to reduce to, so the Old Testament readings still come through for every tradition, which Brian confirmed is right. Against oca.org's leading pair, 2026 goes from 244/339 (72.0%) to 283/339 (83.5%), and that understates it: the metric scores Feb 2 as a miss where we now agree with both antiochian.org and goarch.org. No regression: Greek against goarch.org holds at 333/336, the all-services audit at 352/365, 189 tests pass. january.json changes only in abbreviated_reading_indices, on five level-4 weekdays that now speak the saint's readings rather than the daily cycle. Adds tools/oca/audit_abbreviated.py so this is measurable from now on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Checking Brian's question about the Annunciation on a Lenten weekday -- it does show Hebrews 2:11-18 / Luke 1:24-38, on all three of 2024, 2026 and 2027 -- exposed a gap in the rule committed just before. Floating commemorations were being treated as ordinary readings, because they carry a pdist rather than a month and day, so `ordering` decided among them and the day's own commemoration lost: 12-19 Saturday before Nativity gave the daily pair, not Galatians 3:8-12 10-24 Demetrius Saturday gave the daily pair, not the Departed 07-19 Sunday of the Fathers gave the daily pair, not Hebrews 13:7-16 oca.org prints all three the other way round. Floats are not a saint landing on a day, they are the day, so they now rank ahead of everything including the Sunday rule -- that statistic was measured on saints *displacing* a Sunday, which is a different question. A float is a pdist at or above 1000, the base of FloatIndex. The Lenten soul Saturdays needed data rather than a rule. Their Departed readings carry the day's own pdist and were distinguished only by desc and an ordering of 812/912 -- one tier *below* the daily cycle, so they could never win. Those days are always Saturdays, so unlike the Sunday case static ordering can express it: twelve rows moved to 802/902. Demetrius Saturday needed nothing, being already a float at pdist=1003. Against oca.org's leading pair, 2026 is now 294/339 (86.7%), from 244/339 (72.0%) before this work: 83.5% from the rank rule, 85.0% with floats first, 86.7% with the soul Saturdays retiered. The Annunciation is worth a note of its own: it works because Mar 25 has no fixed-date Epistle or Gospel rows at all: its readings are floats. A tier audit looking only at month/day rows reports "no Epistle/Gospel rows" for a Great Feast, and that is not a fault. No regression: Greek against goarch.org 333/336, all-services audit 352/365, 189 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Brian was notified that St Tikhon's calendar lightens Jul 24 to wine and oil where this app had a full abstention. It is systematic, not one date. _apply_fasting_adjustments had cases for Lent, Dormition and the Apostles'/Nativity fasts and none for the ordinary Wednesday and Friday fast, so outside the four great fasts fast_exception came straight from the data with no rank adjustment. That data disagrees with itself: at feast level 4 the fixture carries 0 for Boris and Gleb and for Constantine and Helen, 1 for Job of Pochaev, and 2 for Sergius of Radonezh. It cannot be made consistent there. fast_exception is baked onto a fixed-date Day row, and whether that date lands on a Wednesday or Friday changes from year to year -- the same structural point as the Sunday rule for abbreviated readings. Verified against holytrinityorthodox.com, which publishes a dietary line per day, looking each commemoration up in a year where its own day falls on a Wednesday or Friday. Boris and Gleb, Anthony of the Kiev Caves, the Synaxis of the Twelve Apostles and Sep 11 all give "Fast. Food with Oil"; the Leavetaking of Theophany gives "Fast. Fish Allowed". A floor of wine and oil is therefore conservative. antiochian.org is no use for this -- it does not keep Boris and Gleb at all -- and oca.org publishes no fasting information. 13 dates a year move from full abstention to wine and oil. All 45 level-4 and above ordinary Wednesday/Friday fast days across 2025-2027 now carry an exception; below level 4 nothing changes. GreekDay is deliberately untouched: it has its own adjustments, the evidence here is Slavic, and Greek feast levels differ -- Jul 24 is level 0 for Greek. To Brian's question of whether this tracks the reading differences: it does not. Of the 13 dates, only Jun 30 appears in either readings audit. Same shape of problem -- hand-maintained per-date data with no rule applied -- but a disjoint set of days. No regression: all-services audit 352/365, abbreviated 294/339, 189 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First measurement of the Slavic data against oca.org, the source it was
compiled from — plus the fixes that measurement turned up. The Greek tradition
was measured against goarch.org and taken from 96.1% to 99.1%; Slavic had never
been measured that way.
Findings live in
docs/oca-audit.md;tools/oca/README.mdmaps each script towhat it produced.
Measurement
97.0%–98.2% a year across five years (2023–2027), on Liturgy Epistle and
Gospel.
One year of data was actively misleading. Cross-tabulating five years
corrected two conclusions drawn from 2026 alone: Oct 31 is not a one-off but
the only date differing in all five years, and Jan 3 is not a fixed-date
problem but the Saturday before Theophany moving across Jan 2–4.
Fixes
St John Kochurov, Oct 31. oca.org gives him a proper Gospel and no proper
Epistle — the Epistle differs every year (Col 2:20, Phil 1:20, Col 2:1,
2 Cor 5:1, 2 Cor 11:31), which is what proves it is the ordinary daily reading;
the Gospel is
John 10:9-16in all five. The app hadHeb 13:7-16andLuke 12:32-40. Gospel repointed, Epistle row removed. Oct 31 now differs byone citation a year instead of three.
Nine commemorations tagged
greekthat oca.org also keeps. Agreektagasserts the Slavic tradition does not keep it, so Slavic users saw none of
these. Three are Kiev Caves saints, which makes the tag self-evidently wrong:
Each checked against the full oca.org listing for its date, not the score.
A further 91 were then read through individually — 100 in total, taking
greekfrom 730 commemorations to 630. Several were plainly never Greek-only:Nilus of Sora, Theodosius of Totma in Vologda, Moses the Hungarian of the Kiev
Near Caves, the 26 Martyrs in the Crimea.
Two were rejected as different people sharing a name and a date, which is
the failure mode the exercise had to guard against: Aug 30 pairs our "Holy New
Martyrs of Serbia" with oca.org's "Saint Spyridon, Patriarch of Serbia" (that
day lists the Serbian Hierarchs and three patriarchs, and no new martyrs), and
Sept 24 pairs our "Stephen the Martyr" with "Holy King Stephen of Serbia" — a
king, not a martyr.
Seven looked thin because our title is generic ("Stephen the Monk", "Julian the
Martyr", "Serapion the Martyr"). Each was checked against the whole day's
listing: in every case exactly one entry out of seven to eleven carries that
name. A rare name kept on the same date is the same saint.
What remains
greekis now dominated by Ottoman-era New Martyrs and Athonitefigures, which is what the tag should mean. Nothing below full token overlap
has been reviewed.
Composites 18 and 24. 18 was
3 Kgs 7:51-8:1, 8:4-7, 9-11, carrying averse oca.org's text does not have and skipping one it does; now
3 Kgs 8:1, 3-7, 9-11, which is functional since 18 is a fall-through.24 was
Lev 26— all 46 verses against a 21-verse reading — now Ephrem's ownspec from anastasis.
Deliberately not done
The reading-selection rule. Everything still differing is one question:
does the ordinary daily reading coexist with a proper one? It runs both ways —
the app drops it where oca.org keeps it (Jan 1, Jan 5, Dec 24) and keeps it
where oca.org replaces it (Oct 31, the moving Saturday before Theophany).
Implementing it would close 4–5 of the 6–10 differing dates a year.
Paused because the harness cannot prove such a change safe.
aget_readingsis on the base
Dayclass shared bySlavicDayandGreekDay, so a changemade for Slavic accuracy is measured for Greek against a different source and
could cost the 99.1% silently. And both audits check Liturgy Epistle and Gospel
only — 894 of 1,446 readings a year, leaving 38% unmeasured on precisely
the feast days the rule governs. Jan 5's Liturgy could be brought into
agreement while its thirteen Vespers lessons and four sets of Hours were
wrecked, and every harness would stay green. The prerequisite is extending the
audit to
/readings/daily/, which lists every service.Converting composites to references. Investigated and rejected. Only three
of eight derivations reach the 59–78% band that correct selections occupy, and
Composites 4 and 5 get worse as candidate verses are added — they are free
adaptations, not selections. The mechanism stays: Ephrem's text, and the
zero-width-space fall-through for 17 and 18.
Commemorations below full token overlap. The 99 full-overlap candidates
have now been read through; weaker matches have not. Name overlap is not
evidence, and Catherine of Alexandria is genuinely Nov 24 Slavic / Nov 25
Greek — a distinction that must not be collapsed. Note also that this compares
same-date only, so it cannot find a saint both traditions keep on different
days.
Notes for whoever touches this next
python-urllib/3.14.That is a keyword filter, not policy: robots.txt allows these paths and asks
for
Crawl-delay: 10, whichtools/oca/fetch.pyhonours. Identify yourself;do not impersonate a browser.
column, and a Lenten day's OT lessons sit in the cells a Liturgy day uses for
Epistle and Gospel. Parsing by column scored the app at 73.7%.
loaddatais additive — it will not remove a deleted row from an existingdev database. The audit kept reporting the removed Kochurov Epistle until it
was deleted explicitly. Production rebuilds from the fixture at image build.
calendarium/tests/data/january.jsonwithindent=4,ensure_ascii=False, no trailing newline, or the diff is 2,300 lines ofreformatting instead of three.
189 tests pass.