Audit the Slavic readings and commemorations against oca.org - #225
Merged
Merged
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
Checked at Brian's request to rule out a missed conversion. It was not missed: lib/core.lib.php's calculateFasting has cases for fast-free, Lent, Dormition and the Apostles'/Nativity fasts -- the same set, order and thresholds this app uses -- and no case for $fast == 1, the ordinary Wednesday and Friday fast. Its Jul 24 row carries daFexc = 0, identical to ours. The rule was never there. Comparing all 366 fixed dates shows how close the conversion is, and which few diverge. fast_exception differs on 7: we are Fast Free where Paul has fish/wine/oil on May 7, May 11, Jul 26 and Oct 1, and grant wine and oil where he has none on Aug 16, Aug 28 and Sep 13. feast_level differs on 6, two of which matter because the rules added recently key on it -- Jun 30 is level 4 here and 3 for Paul, and Nov 16 is 6 here and 5 for Paul, which is what placed it among the great feasts retiered earlier. Also records a schema difference that had not been written down: Paul has two level columns, daFlevel for the feast and daSlevel for the saint, and this app's feast_level is the max of the two on 360 of 366 dates. That is not neutral, because his code uses them differently -- calculateFasting and the reading logic see daFlevel alone, while daSlevel only picks the katavasia, which this app does not implement. Jan 14 is F=0 S=4 for Paul and level 4 here. In that instance the collapse improved things: holytrinityorthodox.com gives Jan 14 "Fast. Fish Allowed" on a Wednesday or Friday, which a level-0 reading could not produce. But feast-level-gated rules here fire on days the original would not have, which is worth knowing before adding more of them. Documentation only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
… service notes Brian's decision (2026-09-02): do not port Paul's values into the fixtures. This data has been revised a great deal since he stopped work, so where the two disagree the assumption should be that ours is the later judgement. orthodox_calendar stays useful for answering "was this ever handled?" -- as with the Wednesday/Friday rank exception, which it never was -- and for corroborating a reading or a date. Also records the daSnote mapping, which had not been written down: it was kept as Day.service_note, and 20 of Paul's 25 notes are present here with identical text. Four of the five absent ones look like an oversight rather than a revision, since this app plainly wants such notes -- it generates "Beginning of Apostles' Fast" in code: pdist -70 Beginning of the Lenten Triodion pdist 0 Beginning of the Pentecostarion Nov 15 Begin Nativity Fast Aug 1 Begin Dormition Fast All four render with an empty service_notes list. One of the three fast beginnings is announced and two are silent, and neither the Triodion nor the Pentecostarion is marked. The fifth absence, a Presanctified note at pdist -17, is generated dynamically by both codebases and is not a gap. Not added, per the decision above. Documentation only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
…sured Two things from the orthodox_calendar comparison. **Service notes.** One of the four apparently-missing notes turned out to be relocated rather than lost: pdist -70 keeps "Beginning of the Lenten Triodion" in feast_name, where Paul has it as a note and leaves daFname empty. The other three were genuinely absent and are added, since this is an oversight rather than a revision -- the app already generates "Beginning of Apostles' Fast" in both SlavicDay and GreekDay, so it plainly means to announce these: pdist 0, Pascha Beginning of the Pentecostarion Aug 1 Beginning of Dormition Fast Nov 15 Beginning of Nativity Fast The fast beginnings are worded to match the generated Apostles' Fast note rather than Paul's terser "Begin Nativity Fast". All three are common, so both traditions get them. **The Wednesday/Friday rank exception does not extend to Greek practice**, on the evidence available, so GreekDay stays as it is -- now a measured decision rather than caution. Tested against antiochian.org's fastDesignation across every ordinary Wed/Fri fast day harvested, 2018-2026. Bucketing by our feast_level is confounded and was discarded: that number is compiled from Slavic sources, which is why Jul 24 is level 0 for Greek. Using antiochian's own feastDayTitle instead -- a plain lectionary slot unless a commemoration claims the day -- gives 52% strict against 33% wine and oil where a commemoration is named, versus 87% against 2% where it is not. So there is a rank effect, but a majority of named days are still strict, which is nothing like the Slavic picture where every sampled polyeleos day was relaxed. Named-yet-strict includes the Apostle Philip, Athanasius of Mount Athos and James son of Alphaeus. Applying the Slavic rule to GreekDay would be wrong in the lenient direction on roughly half the days it touched. Tests not run on this commit, at Brian's direction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Its robots.txt disallows exactly the calendar path used to confirm the Wednesday/Friday rank exception, and I did not check it until after those queries were made. That is an error -- oca.org's robots.txt was checked before harvesting and this one should have been too -- and it is why that sample was not widened. Records the constraint so nobody repeats it, along with what remains available: azbyka.ru is behind a DDoS-Guard challenge, oca.org publishes no fasting, and days.pravoslavie.ru and orthochristian.com serve no robots.txt but are Moscow Patriarchate rather than OCA. Also lists the eight days in 2026 the rule actually changes, and seven controls that carried an exception from the data beforehand, so the printed St Tikhon's calendar can settle it without scraping anything. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
At Brian's direction, five more lookups against holytrinityorthodox.com. Greatmartyr Marina and Adrian and Natalia both give "Fast. Food with Oil", bringing the level-4 sample to seven of seven confirming the rule in the direction it was applied, with nothing contradicting it. Two samples were invalid and the method error is recorded: the date arithmetic found a year where each commemoration lands on a Wednesday or Friday but did not check that the day is an *ordinary* fast in that calendar's own reckoning. Theodore Tyro landed inside Great Lent and Constantine and Helen inside a fast-free week. Filter on the season, not just the weekday. The control is the interesting one. St Sava of Serbia is feast level 3 here, below the threshold the rule uses, and holytrinityorthodox.com relaxes his day to fish. So this app may still be too strict at level 3. That is not necessarily a threshold error -- feast_level is this project's own number and St Sava may be polyeleos in ROCOR reckoning where he is doxology here, the same confound that made the Greek measurement unusable. What it does establish is that the remaining error runs toward being too strict rather than too lenient, which is the safe direction. Also updates the earlier "do not scrape it" note: these lookups were made at Brian's explicit direction, at a handful of manually-spaced requests rather than a crawl. Documentation only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Four more samples at levels 3 and 2 all returned "Fast. Fish Allowed", which looks like evidence the threshold should be well below 4. A control shows it is not: 2026-04-29, a plain Wednesday in the Paschal season commemorating only two minor virgin-martyrs, also returns "Fast. Fish Allowed". The Paschal season relaxes Wednesday and Friday to fish irrespective of rank, so the two April samples were measuring the season. A second control returned "Fast-free Week" for 2026-02-04, the week of the Publican and Pharisee. The two remaining samples are not clean either -- the Synaxis of the Forerunner sits in the relaxed days after Theophany and is a significant feast in itself, and Paul of Thebes at level 2 falls days before the Triodion. So the threshold below level 4 is still unknown. Testing it needs samples drawn from ordinary time, outside the Paschal season, the Triodion, the four fasts and the fast-free weeks; the season filter used here was not strict enough. The rule as shipped rests on seven level-4 confirmations and is unaffected either way. The control also turned up something larger than the question it answered. holytrinityorthodox.com allows fish on Paschal-season Wednesdays and Fridays where this app allows only wine and oil -- Apr 22, Apr 24 and Apr 29 in 2026. The app does give fish on a few days in that stretch, May 6 and May 20, but from per-date data rather than a rule, so the pattern is uneven. If fish is right for the whole span from Thomas Sunday to Pentecost that is 12 to 14 days a year, more than the 13 the rank rule touched. Not changed. One source is not enough for a change that size, and it should come from something that states the rule rather than from sampled days. Documentation only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Brian pointed to OCA's published fasting guidelines, which state the rules rather than showing sampled days: https://www.oca.org/liturgics/outlines/fasting-fast-free-seasons-of-the-church Everything it states outright, this app already gets right -- Trinity Week and the week of the Publican and Pharisee fast-free, Cheesefare a Meat Fast, and the Eve of Theophany, the Beheading and the Elevation as fast days. Its Lenten named list was three-quarters implemented. Wine and oil are permitted on nine named dates when they fall on a weekday in the second through sixth week. Six of the nine are granted correctly in every year checked; Feb 24, Mar 9 and Apr 25 were granted in none. Those three now carry fast_exception = 1. They stay `common` rather than being split: antiochian.org grants wine and oil on Mar 9 in 2020 and 2026 and on Apr 25 in 2024, so those are shared rather than Slavic-only, which also matches what the earlier Greek fasting work concluded. Feb 24 has no qualifying harvested year and its Greek side is assumed. No scoping logic was needed. Week 1 and Holy Week exclude themselves already, because those pdist rows carry fast_exception = 10, "No overrides", and Day.fast_exception takes the max -- Feb 24 correctly stays strict in 2026, when it falls in the first week. Two corrections to the record also go in. The Paschal-season fish candidate is withdrawn. The page lists Bright Week and Trinity Week as fast-free and otherwise treats Wednesdays and Fridays as fast days, with no fish allowance for the Paschal season. This app already gives wine and oil there, which is more lenient than OCA's stated rule, so holytrinityorthodox.com's fish is ROCOR practice rather than a gap here. And the ordinary Wednesday/Friday rank rule added earlier is *not* stated by this document. The page says a Fast Day is strict and calls rank relaxations "local variations". The rule matches OCA's published calendar -- St Tikhon's, and seven of seven on holytrinityorthodox.com -- but not their published guidelines, and should be described that way. The Typikon quotation there is scoped to the Apostles' and Nativity fasts, where it sets thresholds this app does not implement: doxology rank takes wine and oil on Wednesday and Friday and vigil rank takes fish, while the code only ever reduces an exception, never grants one. Noted, not fixed. Tests still not run since Brian's instruction to skip them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
The rule added earlier -- a polyeleos-rank commemoration on an ordinary Wednesday or Friday takes wine and oil -- is removed before shipping. Two reasons, both found after writing it. Its threshold rests on nothing. The Typikon text OCA quotes names *doxology* rank for wine and oil on a Wednesday or Friday and *vigil* rank for fish, which are levels 3 and 5 here. Level 4 is not singled out at all; it was chosen because that is where this app's data happened to disagree with itself. More fundamentally it was another patch on a pile of patches, which is Brian's observation and the reason to stop. Combining the Paschal and festal cycles is done with max() over an index that encodes precedence claims and sentinels alongside dietary rungs, so that max() resolves to the more lenient side on some collisions and the stricter on others, and everything it gets wrong is corrected by hand in _apply_fasting_adjustments. A fourteenth special case is the wrong move. The three Lenten date corrections are kept. Feb 24, Mar 9 and Apr 25 come from OCA's published named list rather than from a rule, are confirmed on the Greek side by antiochian.org for two of the three, and are unaffected by any refactoring of the combination logic. Adds docs/fasting-refactor-scope.md, written while the reasoning was fresh: the diagnosis, the unused DietaryAllowance ladder that already models this properly and is referenced in exactly one display line, the shape to aim at, the size of the migration (about 30 awkward rows out of 858), and the characterisation test to write first. The rank questions are listed there as behaviour decisions to settle once the model can express them, not as part of the refactor. Verified on the final state: 189 tests pass, Greek against goarch.org 333/336, all-services audit 352/365, abbreviated 294/339, Liturgy-only 329/339. january.json returns to its pre-rule values. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
Spotted while tracing aget_abbreviated_readings over Lenten weekdays. One Reading row spelled its source "Sixth Hour" where the other 38 use "6th Hour" -- pk 163, pdist -53, Cheesefare Wednesday, Joel 2:12-26. The row already carried ordering 301, the same slot as the 35 canonical "6th Hour" rows at that value, so this was a spelling divergence and nothing more. It matters because `source` is a public API field and the natural way to select Hours readings is to match the string, which silently skipped this one day a year. No code or template referenced either spelling and the row appears in no test fixture, so the fix is the single string. Verified rendering on three years where the pdist resolves to a different date; 189 tests pass. Also records in docs/oca-audit.md what the same trace turned up about Lenten weekdays, which is a design decision rather than a bug. A plain Lenten weekday passes its Old Testament readings through unreduced, because no group holds both an Epistle and a Gospel and the reduction is a no-op. One carrying a fixed-date commemoration at feast level 2 or above drops them for the saint's pair -- 2026-03-09, the Forty Martyrs, goes from nine readings to two. Clean Week and Holy Week are exempt through the existing fast_exception != 10 guard. oca.org does the opposite there, listing both sets with the Old Testament one first: 28 days over 2023-2027. Kept as-is per Brian, since antiochian.org and goarch.org both publish a single Epistle and Gospel pair for the day. The divergence is from OCA specifically and two of the three sources agree with the current behaviour. data/oca_readings_diff-2026.json is refreshed. Oct 31 now reports three extras against the monthly lectionary rather than one, which is correct: the readings restored there earlier are real, and the monthly view is the lossy one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
brianglass
added a commit
that referenced
this pull request
Sep 8, 2026
The last open follow-up from #225, which was merged before this landed. Checked against holytrinityorthodox.com, the ROCOR calendar, which reckons old calendar so Julian Oct 31 is Gregorian Nov 13. ROCOR commemorates St John Kochurov and gives him no proper readings. The day names him among a dozen commemorations and its scripture line is the plain daily cycle, 1 Thess 5:9-13, 24-28 / Luke 11:23-26. A control rules out the page simply not printing propers: Julian Nov 13, St John Chrysostom, lists John 10:1-9 as Matins Gospel and Heb 7:26-8:2 / John 10:9-16 each labelled "St. John". The format shows propers, with service and attribution, when they exist. So the hypothesis was backwards. Kochurov's three readings are OCA's, and ROCOR is the tradition without them. This app's Slavic data is compiled from oca.org and follows it here, so nothing changes. Recorded as a genuine OCA/ROCOR divergence, since `tradition` has only slavic, greek and common and no axis to express one -- Oct 31 is a known instance if that axis is ever added. It also settles the earlier misstep retrospectively: deleting Kochurov's Epistle and repointing his Gospel would have moved this app toward ROCOR practice by accident, away from its own documented source. Documentation only; no code or data changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX
brianglass
added a commit
that referenced
this pull request
Sep 8, 2026
The last open follow-up from #225, which was merged before this landed. Checked against holytrinityorthodox.com, the ROCOR calendar, which reckons old calendar so Julian Oct 31 is Gregorian Nov 13. ROCOR commemorates St John Kochurov and gives him no proper readings. The day names him among a dozen commemorations and its scripture line is the plain daily cycle, 1 Thess 5:9-13, 24-28 / Luke 11:23-26. A control rules out the page simply not printing propers: Julian Nov 13, St John Chrysostom, lists John 10:1-9 as Matins Gospel and Heb 7:26-8:2 / John 10:9-16 each labelled "St. John". The format shows propers, with service and attribution, when they exist. So the hypothesis was backwards. Kochurov's three readings are OCA's, and ROCOR is the tradition without them. This app's Slavic data is compiled from oca.org and follows it here, so nothing changes. Recorded as a genuine OCA/ROCOR divergence, since `tradition` has only slavic, greek and common and no axis to express one -- Oct 31 is a known instance if that axis is ever added. It also settles the earlier misstep retrospectively: deleting Kochurov's Epistle and repointing his Gospel would have moved this app toward ROCOR practice by accident, away from its own documented source. Documentation only; no code or data changes. Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
4 tasks
brianglass
added a commit
that referenced
this pull request
Sep 14, 2026
#234) * Retag 86 commemorations oca.org keeps; rank the calendar grid's saints A new reverse screen, tools/oca/oca_vs_app.py, asks which of oca.org's 2,968 commemorations for 2026 the Slavic page lacks. #225 asked the opposite question and never looked this way. Of the 93 entries it found only on the Greek page, 90 were read individually and are the same saints under Greek transliterations (Eulogios/Eulogius, Neophytos/Neophytus, Vassianos/Bassian, Kalliniki/Callinica). The 86 rows behind them move from greek to common; greek goes from 630 to 544. oca.org entries matched on the Slavic page go from 822 to 914. Three are held back because the row names someone oca.org does not keep that day: 04-09 Raphael, Nicholas, Irene, & Olympias -- oca.org has no Olympias 04-20 Gregory & Anastasios, Patriarchs of Antioch -- oca.org's Anastasius that day is the Sinaite, not the patriarch 05-19 Theotima & Kyriake -- oca.org has no Kyriake The retag showed up a display problem. Day.minimal_saints, the three names on the calendar grid and in summary_title (and so in RSS and iCal), was a plain truncation of Day.saints. That list puts every day_native row before every additive one, and most storied saints are additive. So on 50 Slavic days a bare harvested name took a storied saint's slot: "Martyr Mertios" over Benedict Biscop on Jan 12, "Marinos the Martyr" over St Patrick on Mar 17. minimal_saints now keeps three by _display_priority, stable within each tier: 1. ranked (rank > 0 or high_rank) 2. with a story 3. the rest Across 2026 a retagged row now holds a slot on 34 Slavic and 21 Greek days, and on none of them is a ranked or storied saint left out. The Alexa skill will now speak the 86 names in both traditions, because _speech_worthy only mutes story-less rows tagged greek. That is about one extra name on each affected day, the same trade #225's retags made. calendarium/tests/data/january.json is regenerated: nine January days gain saints, and several summary_titles change under the new ranking. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX * Keep the Sixth Ecumenical Council on Jan 23 for Slavic readers The traditions keep this council on different days. oca.org lists "the Holy Fathers of the Sixth Ecumenical Council" on Jan 23 and has no council on Sep 14. antiochian.org puts it on Sep 14 in both harvested years. The app had only the Greek Sep 14 row, so Slavic readers never saw it. Retagging that row common would have put it on the wrong day for them. This is the Catherine pattern again: Nov 24 for Slavic readers, Nov 25 for Greek. This adds a slavic row on Jan 23 with oca.org's wording and no story. It links to the same Saint (pk 6846) as the Greek row, so the saint page lists both occasions. The other councils (First, Second, Third, Fifth, Seventh, and the Sunday of the first six) were checked and already match oca.org. A test pins all four combinations of tradition and date. calendarium/tests/data/january.json is regenerated for the extra Jan 23 name. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019nQRjJpPqW89xqzAf1vsEX --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Also in this PR
Abbreviated readings now pick by rank, not row order. These are what the
Alexa skill speaks, and they were reading the ordinary weekday lesson on feast
days — Peter and Paul, the Beheading, the Three Hierarchs. Measured against
antiochian.org and goarch.org, which each publish exactly one pair a day: the
proper wins from about feast level 3 up, the daily wins below it, and on a
Sunday the resurrectional reading wins 7–1. That Sunday split is why the
rule is code rather than data — whether a fixed date falls on a Sunday changes
yearly, while
orderingis static. Floating commemorations (memorialSaturdays, the Sundays of the Fathers and Forefathers) rank ahead of everything,
since they are the day rather than a saint landing on it. 244/339 → 294/339
(72.0% → 86.7%) against oca.org.
Great-feast readings sort ahead of the daily cycle. Sixteen rows moved from
orderingtier 2 to tier 0, so the six level-6 feasts behave like levels 7–8already did.
Three service notes restored — Beginning of the Pentecostarion, of the
Dormition Fast, and of the Nativity Fast — absent here but present in
orthodox_calendar. The app already generates "Beginning of Apostles' Fast", soit plainly meant to announce these.
Three Lenten fasting dates corrected — Feb 24, Mar 9 and Apr 25 are on OCA's
published named wine-and-oil list and were granting nothing.
Deliberately not done
A Wednesday/Friday fasting rank rule. Written, confirmed seven times over
against holytrinityorthodox.com plus Brian's St Tikhon's calendar — and then
backed out before shipping. Its threshold rested on nothing (the Typikon
text OCA quotes names doxology and vigil rank, levels 3 and 5; level 4 was
chosen because that is where our data disagreed with itself), and more
fundamentally it was another patch on a pile. Combining the Paschal and festal
cycles uses
max()over an index that encodes precedence claims and sentinelsalongside dietary rungs, so it resolves to the more lenient side on some
collisions and the stricter on others, with every wrong case corrected by hand.
docs/fasting-refactor-scope.mdrecords the diagnosis, the unusedDietaryAllowanceladder that already models this properly, and thecharacterisation test to write first.
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.
Verified on the final state: 189 tests pass; Greek against goarch.org holds
at 333/336 (99.1%); the all-services audit 352/365; abbreviated 294/339;
Liturgy-only 329/339.