aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* fix(ef): three saints with proper Masses had no readings at allLukasz Kasprzak2026-08-182-0/+18
| | | | | | | | | | | | | | Francis of Paola (2 April), Thomas Aquinas (7 March) and John of God (8 March). Unlike the nine added in the previous commit these are NOT Common- routed -- the Missal prints a proper Mass for each -- they simply had no reading in this repository and resolved nothing. John of God is the one worth a note: his Epistle, Ecclus 31:8-11, is also the Common of a Confessor not a Bishop I, which makes him look Common-routed. He is not; the Gospel differs and the Missal prints the Mass at his own date. With these, every day of 2005-2050 resolves a reading. Nothing in that range comes back empty any more, where before there were four such days.
* feat(ef): the Masses of saints that come from a CommonLukasz Kasprzak2026-08-183-0/+79
| | | | | | | | | | | | | | | | | | | | | | | | | | Nine saints have no proper Mass in the Missal. Its rubric at each one's own date names a Common -- "Missa Statuit, de Communi Confessoris Pontificis I loco", "Missa Iustus ... II loco", and so on -- and only the Oratio is proper. lectio has no Commons concept, so those days resolved no reading at all. Benedict, Frances of Rome, Gregory the Great, Isidore of Seville, Patrick, Perpetua & Felicity, Vincent Ferrer, Ubaldus and Didacus. The readings are written per saint rather than by adding a Commons abstraction. Each Common resolves to exactly one first/gospel pair for the saint that names it, so a table plus an assignment layer would buy indirection and nothing else here; if a future saint needs a Common's OTHER formulary, that is when the abstraction earns its place. They go into the generator's missalOverrides table like the rank and colour corrections, because missalemeum supplies these days with whatever it supplies them and a regeneration would otherwise leave nine saints mute. The table learned two new field names to carry them. Four are pinned in TestTridentineMissalOverrides. Citations are colitur's, verified there against both photographic scans and the rendered page images; its data/ef/commons.sexp header records the three-source method and the per-value evidence.
* feat(ef): the Most Holy Name of Jesus, and the ferias of 2-5 JanuaryLukasz Kasprzak2026-08-184-0/+121
| | | | | | | | | | | | | | | | | | | | | | | | | | | RG 17(a): "festum Ss.mi Nominis Iesu, celebrandum dominica quae occurrit a die 2 ad 5 ianuarii, secus die 2 ianuarii." The Most Holy Name is kept on the Sunday falling 2-5 January and, when no Sunday falls in that window, on 2 January instead. lectio built neither shape, so the day was an ordinary Sunday within the octave and read Gal 4:1-7. The FALLBACK matters more than it looks. The window is four days wide, so in about three years in seven no Sunday lands in it -- in those years there was no Holy Name office at all, a missing II-class feast rather than a misnamed one. The test pins both shapes, checks the fallback does NOT also fire in a year where the Sunday carries the feast, and asserts across 2005-2050 that every year gets it exactly once by one shape or the other. Separately, the ferial days of that window get their own Mass. The Missal's rubric at the feast says it directly: "Diebus ferialibus a 2 ad 5 ianuarii Missa dicitur ut die 1 ianuarii" -- the Circumcision's Mass, Titus 2:11-15 / Luke 2:21. They had been falling through to the Sunday within the octave. Ferial only, and the exclusions are the interesting part: the Sunday carries the Holy Name and its own Mass, and an unoccupied Saturday carries Our Lady's office and hers. 3 January 2026 is such a Saturday and correctly reads Titus 3:4-7, not 2:11-15 -- which works because the BVM check runs first. All four days of 2-5 January 2026 now match colitur.
* fix(ef): Passion week and Holy Week are two weeks, not oneLukasz Kasprzak2026-08-183-18/+97
| | | | | | | | | | | | | | | | | | | | | | efWeek had no Passiontide case, so both weeks fell through to 0 and every day of Holy Week took the slug of its Passion-week namesake: ef-passiontide-0- monday served both Passion Monday and Holy Monday. The two weeks therefore shared one set of readings and Holy Week could not have its own -- Good Friday was reading Passion Friday's Mass. Numbered from Passion Sunday now, so the weeks are 1 and 2 and the slugs distinguish them. The six ef-passiontide-0-* sections are replaced by colitur's twelve rather than renamed, and the reason is worth recording: they were not simply Passion week's Masses. The Tuesday section carried HOLY Tuesday's (Jer 11:18-20 with the Passion according to Mark), which was Passion Tuesday's only by the same collision -- colitur documents that specific mix-up and its own correction of it. Renaming 0 to 1 would have kept the wrong Mass on Passion Tuesday while looking like a clean migration. All twelve are colitur's, verified there against both photographic scans. All six days of Holy Week now match colitur, and so does Passion Tuesday.
* fix(ef): twelve days were serving the preceding Sunday's MassLukasz Kasprzak2026-08-181-0/+62
| | | | | | | | | | | | | | | | | | | | | | Corpus Christi, the Sacred Heart, and the ferias of the first week after Epiphany and the first week after Pentecost had no lectionary entry, so each fell through the walk-back and read the Mass of the Sunday before it. Corpus Christi -- a I-class feast with one of the best-known formularies in the Missal -- was reading Trinity Sunday's. RG 299 is why the first weeks need naming where the others do not: "Item propriam Missam habent omnes feriae..." -- those ferias have proper Masses, and the walk-back that serves the rest of the year correctly is wrong for them. Citations are colitur's, verified there against both photographic scans. They were added rather than derived: a comparison of the two lectionaries found the 110 shared slugs agree on EVERY citation, so the divergence was entirely entries lectio lacked, not entries it had wrong. Twelve of the 43 colitur has and lectio lacked. The other 31 name days lectio calls something else, so adding them verbatim would be dead data; those need the slug question answered first and are deliberately not touched here.
* feat(ef): Rogation Monday and Tuesday (RG 87)Lukasz Kasprzak2026-08-183-0/+79
| | | | | | | | | | | | | | | | | | | | | | | | RG 87: "Litaniae minores seu Rogationes, per se, assignantur feriis II, III et IV ante festum Ascensionis Domini." Easter+36 and +37 are that Monday and Tuesday. RG 128(d) gives them violet -- "for the procession and Mass of the Greater and Lesser Litanies" -- a penitential note inside white Paschaltide. lectio computed no Rogation days at all and showed a plain paschaltide feria. The WEDNESDAY is deliberately not built, and the test asserts its absence. Easter+38 is by construction the Vigil of the Ascension, II class, which wins the day outright; what the rubric asks for there is a COMMEMORATION, and this function returns one office per day. colitur reaches it through a movable-date entry in its sanctoral overlay. Extending the Rogation branch to +38 to "complete" the rubric would silently displace the Vigil, so the test pins the Vigil rather than leaving the omission to a comment. Rank is left as the feria's: these are IV-class days and any III-class saint displaces them, which is what makes the office rare. In 2026 all three are impeded and none appears; 2027 has the Monday unimpeded, and lectio and colitur are byte-identical across 2-5 May that year. One oracle allow-list entry: missalemeum builds no Rogation days either and shows a white feria, so it is the outlier here rather than lectio.
* fix(ef): the weekdays within the Octave of the Nativity have their own MassLukasz Kasprzak2026-08-182-0/+88
| | | | | | | | | | | | | | | | | | | | | | | | | 29, 30 and 31 December are named days in the Missal's calendarium -- "De V die infra octavam Nativitatis Domini, II classis" and so on -- with a direct formulary, "Diebus infra octavam Nativitatis Domini": Titus 3:4-7 / Luke 2:15-20, and each date's own rubric pointing at it ("Die 29 decembris ... Missa Puer natus est nobis, ut supra"). lectio treated them as ordinary Christmas ferias, so they fell back to the preceding Sunday and served "Dominica infra octavam Nativitatis Domini" (Gal 4:1-7 / Luke 2:33-40) -- a different heading, for the Sunday specifically. Worth recording because it is not a guess: colitur made the IDENTICAL mistake, gave these three days the Sunday's citation, measured it against real years and reverted it. Its bootstrap_lectionary.ml keeps the rejection on record with the scan references for both headings, which is how this one was diagnosed rather than re-derived. Only the weekdays. When 29-31 December falls on a Sunday the day really IS Dominica infra octavam and keeps the Sunday's Mass -- 2030-12-29 is the case, and it is asserted, because a fix applied by date alone would pass on the weekdays and silently swallow the Sunday. Mutation-tested: dropping the Sunday exclusion reddens exactly that assertion and nothing else.
* feat(ef): the Mass of Our Lady on Saturday (RG 309(a))Lukasz Kasprzak2026-08-182-0/+108
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 78 gave the day Our Lady's office and its white colour; this gives it her Mass. RG 309(a): "Missae de sancta Maria in sabbato ... iuxta temporum diversitatem" -- the Missal prints five formularies and the season selects among them. Without it the day was kept as Our Lady's and then read the FERIA's Mass, so a Saturday in Septuagesima announced Our Lady and read the parable of the labourers. colitur hit and fixed the identical bug in its own v0.3.0. The five, with the two seams that are easy to get wrong: Advent Isa 7:10-15 / Luke 1:26-38 Christmas Time Titus 3:4-7 / Luke 2:15-20 ...and on until the Purification (2 February), not merely to the end of Christmas Time thereafter Ecclus 24:14-16 / Luke 11:27-28 Paschaltide Ecclus 24:14-16 / John 19:25-27 -- same first reading, different gospel, which is why the test asserts the gospel separately Citations are colitur's, verified there against both photographic scans. The Advent formulary is unreachable as the Saturday office -- Advent has no IV-class ferias -- and is kept anyway, because RG 309's subject is the Masses themselves and a missing branch would fall through silently if the rank rules ever changed. Guarded on the office rather than the day: a sanctoral feast that outranks the Saturday keeps its own readings, so the observed slug must still be the temporal one. All twelve BVM Saturdays of 2026 now agree with colitur on readings, where none did before.
* feat(ef): the votive Office of Our Lady on Saturday (RG 78)Lukasz Kasprzak2026-08-182-0/+70
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 78, Caput IX "De sancta Maria in sabbato": "In sabbatis, in quibus occurrit Officium de feria IV classis, fit de sancta Maria in sabbato." A Saturday whose office would otherwise be a IV-class feria keeps Our Lady's office instead, and it is white -- RG 431(e) classes that Mass as a "Missa votiva IV classis ... de B. Maria Virg.", RG 121(a) gives a votive Mass the colour of the feast-type it answers to, and RG 120(b) makes feasts of the BVM white. Smaller than it sounds, because the protasis is already computed. "A IV-class feria" is exactly what rank still being RankClass4 means at that point: every branch above has promoted Advent, Lent, Passiontide, the Ember days, the privileged ferias and the Christmas octave out of it. The SLUG IS DELIBERATELY UNCHANGED. colitur, which has had this office since its v0.3.0, does the same: a bespoke slug would recur many times a year and break the one-slug-per-liturgical-year invariant, and the readings are selected by the Mass formulary rather than by the slug. Only the colour moves. It is also the temporal office only -- a sanctoral feast that outranks the Saturday still wins and brings its own colour, exactly as before. Result: lectio and colitur now agree on the colour of EVERY DAY of 2026. Zero mismatches, where this class alone was nine days that year and 439 rows across 2005-2050 -- the largest single divergence class between the two engines. Pinned in both directions, because the tempting wrong fix is to whiten every Saturday: Lent and Advent Saturdays are III-class violet ferias and must stay violet, and Holy Saturday must too. Mutation-tested -- dropping the IV-class guard reddens the test on the Lenten Saturday, not on the per-annum ones.
* fix(ef): weeks after Epiphany count from the first Sunday, not from EpiphanyLukasz Kasprzak2026-08-182-3/+76
| | | | | | | | | | | | | | | | | | | | | | efWeek anchored the Time-after-Epiphany week number at 6 January, which put every week of the season one too high -- 14 January 2026 came out as week 2 when the first Sunday after Epiphany was 11 January and the week running from it is the first. The error persisted from Epiphany until Septuagesima cut the season short, so it was wrong for most of January and February every year. The Sunday is the anchor because it carries the Mass the week is named for, "Dominica I post Epiphaniam", and its ferias follow it. Epiphany itself is a feast inside Christmas Time (RG 72), not the head of a numbered week -- which is the same distinction the Christmas Time boundary fix just made, showing up again one function along. Week numbers now match colitur day for day through the season. The test pins the ordinary years AND the edge that a naive fix gets wrong: when Epiphany itself falls on a Sunday, "the first Sunday AFTER Epiphany" is the following week, so the helper starts its search on 7 January rather than the 6th. It finds such a year in 2005..2050 rather than hardcoding one. Mutation-tested: restoring the 6 January anchor reddens it.
* merge: RG 72's Christmas Time boundary, and the season/slug split it neededLukasz Kasprzak2026-08-183-13/+129
|\ | | | | | | | | Separates the liturgical season from the season that names slugs and numbers weeks, so the boundary could move without renaming every slug in the window.
| * fix(ef): Christmas Time runs to 13 January (RG 72)Lukasz Kasprzak2026-08-183-13/+129
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 72: "Tempus natalicium decurrit a I Vesperis Nativitatis Domini usque ad diem 13 ianuarii INCLUSIVE." 6-13 January is the Epiphany section OF Christmas Time, not the start of Time after Epiphany. RG 119(a) backs the same boundary from the colour side, white "usque ad expletum tempus Epiphaniae". lectio ended Christmas Time on 5 January, so eight days a year came out green that should be white, and Epiphany itself reported the wrong season. NOT a one-line boundary change, which is why an earlier attempt was reverted rather than shipped. efSeason both named the slugs and reported the season, so moving the boundary renamed every slug in the window -- ef-time-after-epiphany-* became ef-christmas-* -- and orphaned the ef-time-after-epiphany-sunday-1 lectionary key. The two are now separate axes: efSlugSeason names slugs and numbers weeks; unchanged behaviour efSeason the liturgical season, which the colour follows; RG 72's The split is not a new idea in this file. The resumed-Sundays branch already does exactly this and says so -- "Season stays time-after-pentecost (calendrical); the Epiphany slug only routes the readings" -- it simply had no name, so the one place that needed it could not reuse it. Result, checked against colitur across all 365 days of 2026: SEASON now agrees on every single day, where it previously differed on eight. Colour differences drop to nine, every one a Saturday and every one the BVM Saturday Office (RG 78, colitur C17) which lectio does not build. Slugs and week numbers are byte-identical to before. The oracle's season axis now consults the allow-list and excludes excused days from its threshold. Neither was true before, because no cited divergence had ever BEEN a season difference -- the January window showed up as a colour one, since the wrong season produced the wrong colour too. With the season right, what is left is a season difference against missalemeum, and an axis whose threshold is a t.Fatalf would have failed regardless of any allow-list. TestTemporalEFChristmastideBoundary pins the boundary AND the split, mutation- tested both ways: reverting the boundary reddens it, and re-merging the two seasons so the slug is built from the liturgical one reddens it differently, naming the orphaned lectionary key.
* fix(ef): twelve RG 124 colours -- missalemeum has the rule invertedLukasz Kasprzak2026-08-184-12/+99
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 124, "De coloribus paramentorum", section C, both photographic scans word for word: 124(b) gives red to "Sanctorum Apostolorum et Evangelistarum, in eorum die natalicio, excepto festo S. Ioannis (27 decembris)", and 124(e) to "Sanctorum Martyrum, quorum colitur aut martyrium". Red is for Apostles, Evangelists and Martyrs. A Confessor, Doctor or non-martyr Virgin is white. missalemeum has twelve of these INVERTED IN BOTH DIRECTIONS: ten confessors, doctors and virgins in red (Ephrem, Julia of Falconieri, John Gualbert, Camillus de Lellis, Jerome Emiliani, Martha, Alphonsus Liguori, Augustine, Rose of Lima, John of San Fecundo), and two actual martyrs in white (Apollinaris and Josaphat, both Bishop and Martyr). Both directions failing is why this reads as one rule applied backwards rather than twelve separate slips, and why they are corrected as a block. Adjudicated by colitur against the scans -- its C18 carries the per-slug reasoning and its M21 the oracle side, verdict colitur. Two of its fourteen, conversion-of-st-paul and chair-of-st-peter, already agreed here. Found by a full-year sweep comparing clectio's output against colitur day by day, not by the patch tool that produced the earlier corrections. That tool reads colitur's sanctoral.sexp directly and so misses everything in adjustments.sexp, the overlay where all twenty of colitur's colour edits actually live -- its SECOND structural blind spot, after temporal days. All twelve go into the generator's missalOverrides table, so regeneration preserves them, and into TestTridentineMissalOverrides, now sixteen pinned fields. Mutation-tested in BOTH directions: reverting a martyr to white and a confessor to red each redden the test with the rubric named. Pinning only one direction would have let a careless "make them all white" fix pass ten of twelve. The oracle allow-list gains one entry covering the twelve dates in both years.
* fix(ef): Good Friday is black (RG 128(b) + RG 132)Lukasz Kasprzak2026-08-182-6/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | This file's own comment called RG 132's black "a separate, unmodelled gap". It is modelled now. RG 128(b)'s exception list carries Good Friday in the same sentence as Holy Thursday's -- "Actione liturgica feria VI in Passione et Morte Domini usque ad Communionem exclusive" excepts the day from Passiontide's violet -- and RG 132 assigns black to it. Adopted from colitur, which closed the same gap against the Missal in its v0.4.0. The rubric is per-action and this model carries one colour per day, so black is the day's principal colour, the same acknowledged limit the Palm Sunday blessing already has. missalemeum's own colour set for the day is "bv", black first, so the oracle test accepts this without a new allow-list entry. Found by cross-checking clectio's output against colitur date by date, NOT by the patch tool that produced the earlier eight corrections. That tool compares colitur's sanctoral data against this repo's calendar ini, so a temporal day -- computed in code on both sides, in neither file -- is structurally invisible to it. Its docstring now says so. TestTemporalEFHolyThursdayColour asserted Good Friday was violet "(unchanged)", encoding the gap; renamed to TestTemporalEFTriduumColours and updated. A test asserting the absence of a feature passes for exactly as long as the feature is absent, which is not the same as being correct. Holy Saturday is still pinned violet in the other direction, so a careless "the whole Triduum is black" change fails there.
* feat(gen): teach the EF generator to preserve the Missal correctionsLukasz Kasprzak2026-08-183-11/+166
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The four calendar corrections adopted from colitur are not in missalemeum, so re-running gen-sanctoral-ef.go silently reverted them. Warning about that in three places was the stopgap; this fixes it. The generator now carries a missalOverrides table -- slug, field, required value, and the authority for it -- applied after every harvest and collision fix-up has settled, so the Missal's value is the last word. Regenerating is now safe; hand-editing the generated file is not, and both the file's header and the generator's comment now say which way round that is. An explicit table rather than "preserve whatever the existing file had", which is how the name.<lang> preservation beside it works and would have been less code. Preserving from the file cannot distinguish a deliberate correction from staleness: if missalemeum ever fixes one of these, a preserve-from-file rule would keep overriding it forever with nobody the wiser. Naming each override with its rubric makes an obsolete one findable by reading four lines. The apply step reports "already correct upstream" when it finds one, which is the signal to retire it. It FAILS rather than warns when an override names a slug the run did not harvest. A rename upstream would otherwise drop a correction silently, which is the precise accident the table exists to prevent. TestTridentineMissalOverrides pins all four values from the other side, so a regeneration that stopped applying them fails the suite rather than only failing quietly. Mutation-tested: reverting the Assumption vigil to missalemeum's white reddens it with a message naming the cause. It also asserts the Ascension's vigil is NOT violet -- RG 128's rule is "outside Paschaltide" and that one is inside it -- so a careless "make every vigil violet" fix fails too.
* docs(caldata): the EF data is no longer purely generated -- say soLukasz Kasprzak2026-08-183-0/+55
| | | | | | | | | | | | | | | | | | | Both ini headers described this data as generated from missalemeum, and the generator described its own output as the file. Neither is true since the eight corrections landed, and the gap is not cosmetic: missalemeum does not carry any of them, so running scripts/gen-sanctoral-ef.go would silently revert all four calendar fields, with nothing to notice it. The two ini headers and the generator's own doc comment now each carry the list of hand-corrected fields, the rubric behind each, and the warning that a regeneration reverts them. Deliberately repeated in both places rather than cross-referenced from one: either can rot, and repeating the list means the other still shows it. Also records what the six allow-listed oracle days actually mean now. The oracle is not wrong to flag them -- missalemeum is simply the party that disagrees with the Missal, which is a different situation from the one that test was written for.
* merge: adopt colitur's EF correctionsLukasz Kasprzak2026-08-183-8/+67
|\ | | | | | | | | Eight fields where the 1962 Missal decides against lectio's inherited values, each with its rubric, plus the two oracle allow-list entries they require.
| * fix(ef): adopt eight corrections from colitur, with their citationsLukasz Kasprzak2026-08-183-8/+67
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | lectio's EF data has been the upstream for colitur, whose data was bootstrapped from this ini. colitur has since validated that data against the 1962 Missal itself, and these eight fields are where the two now disagree and the Missal decides against us. Each carries the rubric. Calendar. St Ubaldus (16 May) and St Didacus (13 November) become III-class feasts rather than commemorations: the Missal's own universal calendarium ranks both "III classis" outright with no commemoration rubric, and each has its own Mass entry in the Proprium taking its readings from a Common with only its Oratio proper -- which a bare commemoration never has. Found by auditing all 290 of colitur's fixed-date entries against that calendarium; these two were the only status defects in the file. The Vigil of the Assumption becomes violet from white and the Vigil of St Lawrence violet from red: RG 128 gives violet to vigils of II and III class outside Paschaltide, and its sole exception is the Ascension's vigil, inside Paschaltide, which is white and is untouched here. Lectionary. Both Ember Saturdays carried the wrong saint's Mass entirely -- St Thomas the Apostle's under ef-advent-ember-sat and St Matthew's under ef-september-ember-sat, in both cases because 21 December and 21 September fall on a Saturday in the same six years and a bootstrap generalised one year's coincidence into a template value. Two oracle allow-list entries, both placed ahead of the BVM-Saturday entry deliberately. When 16 May or 13 November falls on a Saturday, that entry's predicate also matches and would absorb the divergence under a reason no longer true of it -- it says both engines agree the day is unimpeded, and the point here is that the day IS impeded. The vigil entry excludes Sundays for the mirror reason: RG 33 omits a vigil falling on one, and without the guard 2026-08-09 is stolen from the RG 33 entry that actually explains it. Six days of the 730-day oracle window are affected. Readings are untouched by that test, so the two lectionary corrections cost it nothing.
* caldata: two Judith citations lost a chapter boundaryLukasz Kasprzak2026-08-171-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | The Assumption's epistle is Iudith 13, 22-25 et 15, 10 -- two chapters. It was recorded as "Judith 13:22-25; 13:15; 13:10", carrying chapter 13 across the boundary and inventing two verses that are not in the Mass at all, on a I-class feast. The Seven Sorrows' is Iudith 13, 22 et 23-25. It was recorded as "Judith 13:22; 13:25", keeping only the range's endpoint. Both verified in the photographic scans of the 1962 Missal: Assumption IN ASSUMPTIONE B.M.V. "Iudith 13, 22-25; 15, 10" Seven Sorrows SEPTEM DOLORUM B.M.V. "Iudith 13, 22 et 23-25", printed identically at its Mass and in the votive Mass of the same feast. Found by comparing a full liturgical year (2028-12-03 .. 2029-12-01) against missalemeum's live API, day by day, while giving colitur a lectionary of its own. 333 of 364 days already agreed; these were two of three genuine divergences in the remainder. The third was St Monica (4 May): missalemeum serves Prov 31:10-17, this data serves 1 Tim 5:3-10. The Missal gives her a proper epistle -- "Lectio Epistolae beati Pauli Apostoli ad Timotheum", 1 Tim 5, 3-10, "Carissime: Viduas honora, quae vere viduae sunt" -- in both scans. No change: the oracle is wrong there, not this data.
* release: v0.46.1v0.46.1Lukasz Kasprzak2026-08-171-1/+1
|
* changelog: 0.46.1Lukasz Kasprzak2026-08-171-0/+3
|
* caldata: the Lenten Ember days were serving Lent I Sunday's MassLukasz Kasprzak2026-08-172-3/+65
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Three lectionary sections were keyed ef-lent-1-{wednesday,friday,saturday} while temporal_ef.go's efEmberSlug computes ef-lent-ember-{wed,fri,sat}. The lookup in caldata.Readings takes the observed slug and has no alias table, so it missed the entries entirely and fell through to the preceding-Sunday fallback. Every Lenten Ember day since the data was added has served Lent I Sunday's Mass -- three days a year, in a season that prints a proper Mass daily. The values were already right; only the keys were wrong, and they were stale rather than mistaken: they predate Lent being added to efEmberSlug, and scripts/genlect.go keys off day.Observed.Slug, so re-running it would already write the correct names. Advent and September were never affected -- both already use the -ember- form. Renamed, and verified the whole file: every one of the 119 section names is now a slug the calendar actually computes, checked by sweeping 2005-2050. Those three were the only dead keys. Added TestEFLectionaryKeysAreReachableSlugs to make the class detectable rather than just this instance. Mutation-tested: reverting the three keys fails it, naming all three. Found by differencing against colitur, the sibling OCaml engine, while giving it a lectionary of its own. Worth recording how nearly it escaped: colitur inherited the same wrong keys from this file during its bootstrap, so both engines produced the same wrong Mass and the differential between them was silent. It only surfaced when colitur's data was checked against the Missal itself. Two implementations agreeing is not evidence when one was seeded from the other.
* lectio-ef-dump: emit the Epistle and Gospel citationsLukasz Kasprzak2026-08-151-20/+52
| | | | | | | colitur's differential compares reading citations from this release onward, and needs them per day rather than per lectionary key -- this engine resolves a feria to the preceding Sunday's Mass itself, which is exactly the behaviour the differential has to check.
* NOTICE: the Wujek corpus is public domainLukasz Kasprzak2026-08-141-12/+6
| | | | | | | | | | Drops the copyright caveat on the ~300 deuterocanonical verses sourced from the 1962 edition, and the redistribution restriction that followed from it, on the author's ruling. The source edition stays recorded as provenance so the corpus can still be re-derived or checked. The SBLGNT attribution is untouched: CC BY 4.0 requires it of anyone redistributing the text, which a fullbible binary does.
* release: v0.46.0v0.46.0Lukasz Kasprzak2026-08-141-1/+1
|
* changelog: 0.46.0Lukasz Kasprzak2026-08-141-0/+3
|
* Merge branch 'polish-ui-and-calendar': the gomobile facade and the EF ↵Lukasz Kasprzak2026-08-1429-2969/+7616
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | calendar fixes Two bodies of work that shared a branch. The gomobile facade (2026-08-03..05): mobile.PartLabels, Days, and the observed rank on DayInfo, so dlectio stops hardcoding part IDs and rank strings; the 1962 part labels become i18n data; the documented gomobile bind command is corrected so it reproduces the shipped .aar. The EF calendar fixes (2026-08-12): seven defects found by differencing this engine against colitur, a second 1962 implementation built from the Missal's General Rubrics rather than from this codebase. RG 96 transfers were not skipping II-class days; a II-class privileged feria was not yielding to a feast; Sunday ranks, the two Rose Sundays and Holy Thursday's colour were wrong; and scripts/gen-sanctoral-ef inferred ranks, deduped and tagged classes wrongly, which put 15 III-class feasts into the shipped tridentine-calendar.ini as bare commemorations and dropped four entries outright. Holy Thursday was violet in both engines, which is how a shared lineage hides a defect: this project's ini is generated from missalemeum and colitur's data was bootstrapped from here, so an error inherited by both is invisible to a differential. It took the Missal itself to see it. The EF oracle test now asserts rank and colour, not season alone. One known gap is recorded in the source rather than fixed, as out of scope: RG 95 chained transfers (calendar.go).
| * Merge branch 'fix/ef-precedence-defects': seven EF calendar defectsLukasz Kasprzak2026-08-1213-2955/+6631
| |\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fixes seven defects in the EF calendar, each found by differential and oracle comparison against an independently-written engine and each backed by a cited paragraph of the Rubricae Generales verified against the 1962 Missal: RG 96 transfers must skip II-class days (the Precious Blood was landing on the Visitation) RG 91 a II-class privileged feria yields to an equal-class feast (St Matthew was losing to the September Ember Wednesday) RG 11 all Sundays of Advent, Lent and Passiontide are I class (only Advent I was), which also settles St Joseph on a Lent Sunday RG 131 Rose on Gaudete and Laetare, which the EF path never emitted RG 122 Holy Thursday is white and the sanctoral generator itself, whose rank inference had tagged 15 III-class feasts as commemorations, dropped four entries to slug collisions, and mis-tagged three class fields. The EF oracle test asserted Season only, which is why none of this ever failed. It now asserts rank and colour, with a cited allow-list. Two commemorations had been deleted on a primary-source claim the primary source contradicts: the Archivum Liturgicum transcription silently drops commemoration lines where the photographic scans carry them. Six of the seven affected dates are now present; the seventh (25 December) is blocked by an ingestion limit that reads only the first of three Christmas Masses, recorded at its cause. Known gap, recorded in source: RG 95/97/98 chained transfers, where two I-class feasts translate to the same day.
| | * gen-sanctoral-ef, caldata: fix round 3 -- guard coverage, rank pins, name ↵Lukasz Kasprzak2026-08-122-41/+174
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | test, Anastasia Second external re-review returned Spec pass on round 2 (all ten prior findings addressed, C1/C2 fixed at the root, mechanism claims held under mutation) and found two blocking items in the I3 guard itself, plus three recommended hardenings. All verified independently before fixing. BLOCKING 1: refYearExplainsAbsence's own doc comment said the id-rank exclusion covers "6-31 December"; the code implemented `Day() >= 26`. A typo (26 -> 6), but the wrong kind to have on the one comment this whole review chain exists to keep honest -- fixed as part of the rewrite below, not left as an isolated one-character correction. BLOCKING 2: the guard covered only 6 of the 13 MM-DD values round 1's own temporal_ef.go changes actually made refYearExplainsAbsence couple to. Measured, not just reasoned about: running the function's body against the branch-point engine versus HEAD over the six reference years flips its verdict on 50 dates across 12-17 through 12-23 (round 1's late-Advent promotion, RG 91 entry 18, a 140-day change) AND 12-26 through 12-31 (the Nativity-octave promotion, RG 67/68, already guarded). The late-Advent half was unguarded. No live bug today -- confirmed by regenerating: the ini is BYTE-IDENTICAL before and after this fix. The only sanctoral entry in 17-23 December is `thomas` (21 December), reached via harvestDate's `obs` (observed-office) path, never refYearExplainsAbsence's commemoration-id-trust path at all. Widened the guard to 17-31 December anyway, on the side of the known-safe default (RankCommemoration) rather than wait for the first real entry in that range to repeat I3's exact failure shape. The two sub-ranges are NOT the same strength of evidence, and the doc comment says so explicitly now: 26-31 December rests on a positive RG 68(d)/(e) citation naming Thomas Becket and Silvester directly as bare "Commemoratio, no class"; 17-23 December is a precautionary exclusion with no equivalent citation -- RG 91 entry 18 ranks the FERIA, not any commemoration that might coincide with it, and (per defect 2's own finding) a genuine class-2 feast there would actually WIN against the ferias's own privilege, so "the day is class-2" does not reliably explain a class-2 saint's absence here the way it does for the Nativity octave's two named cases. Recorded as a real asymmetry, not smoothed over. RECOMMENDED 3: rank = commemoration is now pinned for all four entries this task's two review rounds touched -- romanus, eusebius-confessor (C2), thomas-becket, silvester (I3) -- not just their presence and date. `git grep` before this commit returned zero hits for thomas-becket or silvester rank anywhere in *_test.go; a future regeneration could have rewritten either back to class-4, the exact I3 failure mode, with the suite green throughout. RECOMMENDED 4: TestTridentineNamesPreservedAcrossRegeneration rewritten on both axes the review found loose. It counted name.pl only -- a hardcoded single language, the identical "whitelist of two" mistake C1's own generator fix exists to stop repeating, just moved into the test instead. Now DISCOVERS every name.<lang> key actually present in the data (so a regeneration dropping name.la, or losing a future name.de, is caught the same way as name.pl) and asserts the discovered language set is exactly {en, pl} -- not just each count. The >= 315 floor had 7 entries of slack (the review proved 6 missing Polish names still passed it); tightened to the exact, independently verified true count (322), zero slack. RECOMMENDED 5: the 25 December Anastasia gap and its cause are now recorded, not just her absence. Two compounding, independently checked causes: fetchOnce reads only `data[0]`, missalemeum's FIRST of Christmas Day's three Masses, so a commemoration attached to a second or third Mass (the calendarium's own "In secunda Missa: Commemoratio S. Anastasiae Mart.") is structurally invisible to this harvester for ANY date, not just this one -- but ALSO, checked live, missalemeum's own "commemorations" list is empty on all three of the date's records, not just the first, so a fetchOnce rewritten to merge all of a date's Masses would still not recover her. Documented at both fetchOnce's own definition and the PRIMARY-SOURCE NOTE, since the two facts belong to different questions (a real code limitation worth fixing someday vs. an upstream data gap this generator cannot close at all). Witnesses: TestTridentineCommemorationRanksPinned (new), TestTridentineRomanusAndEusebiusPresent (extended with rank), TestTridentineNamesPreservedAcrossRegeneration (rewritten). No pre-fix failure to report for the two new/tightened tests specifically -- these are regression GUARDS against a bug class already fixed in round 2, not fixes for a currently-red state; their value is in what they would now catch, not what they catch today. internal/caldata/ tridentine-calendar.ini is NOT regenerated by this commit -- confirmed byte-identical before and after re-running the generator, exactly as "no live bug today" predicts.
| | * lectio-ef-dump: add name_en/name_pl columnsLukasz Kasprzak2026-08-121-8/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The verification instrument this task's own diff comparisons run against emitted season/week/slug/rank/colour but no display name at all, so it was structurally incapable of seeing the 322-line name.pl deletion (fix round 2) -- the season/rank/colour columns it already printed were all still correct, since name is a wholly separate field naming.CelebrationName reads independently, and no diff against this tool's own prior output could ever have caught the regression. Appends two fixed columns after colour (before the existing +other tokens): the observed celebration's own name.en and name.pl (spaces replaced with "_" so the line stays whitespace-delimited; "-" for an empty name, matching the week column's own convention). Format is documented in the package doc comment as a departure from colitur's matching day-line format: a straight diff against colitur's output must now ignore these two trailing-before-others fields.
| | * oracle_ef_test: three structural coverage gaps in the strengthened testLukasz Kasprzak2026-08-121-5/+38
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Cheap fixes flagged in review, all confirmed against the committed snapshot before being applied: 1. An unmapped season phrase skipped the RANK AND COLOUR checks too, not just the season comparison -- `continue` in the wrong place. Confirmed live: neither Holy Thursday ("maundy"/"holy week" do not match the title "Holy Thursday" itself) nor any of the six September Ember days (no "ember" case exists at all; the Advent and Lent Ember days only ever passed by an incidental substring match on "advent"/"lent") had any oracle coverage at all -- reverting the Holy Thursday colour fix left this test green. Season skip and rank/colour checks are now independent. 2. Colour membership alone cannot catch a Rose regression: violet is a member of every rose/violet pair by construction (Gaudete/ Laetare), so "got violet, want one of [rose violet]" passed even with RG 131's Rose support removed entirely. On the day the pair actually names (oracle rank 1, the Sunday itself, not a weekday reusing its propers), a colour set containing rose now demands rose specifically. 3. `has("sexagesima")` never matched missalemeum's own ligatured "Sexagesimæ" -- confirmed in the committed snapshot: the ligatured form appears 10 times, the unligatured form only 4, and every ligatured instance mapped to season "" (skipped from ALL coverage, not merely a season miss, given finding 1 above). Normalised once, generally (æ -> ae), not as a single hardcoded word, so any other ligature this generator's own data may carry is covered too. Net effect on TestOracleEF: 730 checked (up from 691), 29 skipped (down from 39) -- the 10 reclaimed by fix 3. Still green: 0 unallow-listed rank or colour mismatches over the full snapshot.
| | * calendar: record the RG 95 chained-transfer gap in the sourceLukasz Kasprzak2026-08-121-0/+25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | transferIfImpededEF resolves one candidate's own transfer walk in isolation and has no way to notice a SECOND, separately-transferred I-class candidate landing on the same destination day -- St Joseph (19 March) and the Annunciation (25 March) can both walk to the Monday after Low Sunday in the same year (2008, 2035, 2046, e.g. 2035-04-02: annunciation-of-the-blessed-virgin-mary +joseph-spouse- of-the-bl-virgin-mary). RG 95 grants the right of translation "solummodo festis I classis" to I-class feasts only, so both candidates genuinely have it, and the collision they land in together is an ordinary RG 97/98 occurrence question this function does not resolve: pickEF's plain alphabetical slug tie-break settles it instead of re-walking the loser. RG 98 itself supplies the determinism rule this collision needs and does not have: "in paritate autem Officium prius impeditum praecedit" -- at equal table position, the office impeded FIRST takes precedence, which is chronological (Joseph, impeded on the 19th, before the Annunciation's own walk begins on the 25th) and may favour Joseph over the current alphabetical fallback. No functional change -- this collision is left unfixed, defensible against scope (it needs resolving occurrence between two ALREADY- TRANSFERRED candidates, not a single one, a bigger shape than this function currently has). Leaving it unrecorded was not defensible: nothing in internal/calendar/ named RG 95, 97, 98, or chained transfers anywhere before this comment.
| | * gen-sanctoral-ef, caldata: fix round 2 -- review found five real problemsLukasz Kasprzak2026-08-124-97/+641
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | External review of the seven-defect fix (round 1) confirmed all seven correctly and structurally fixed, then found five further problems in what shipped alongside, two of them critical. All five verified independently before being fixed, not applied on the review's say-so alone -- see each item below for the primary-source check performed. CRITICAL 1: the regeneration destroyed all 322 Polish display names. main() preserved name.la across a regeneration (missalemeum has no Latin titles) but had no equivalent for name.pl, and never emitted one -- name.pl count went 322 -> 0 (confirmed: `git show 2386a45:internal/caldata/tridentine-calendar.ini | grep -c '^name.pl'` = 322; the pre-round-2 file = 0). naming.CelebrationName's own name[lang] -> name.en fallback then silently substituted English for every Polish EF display, reaching mobile.Day(date, "ef", version, "pl") -- a shipped dlectio entry point -- with no error anywhere in the chain, and nothing in this repo's test suite asserting any name.* field at all. Fixed at the root, not by re-adding name.pl specifically: `entry.la` (one hardcoded language) is replaced by `entry.otherNames map[string]string`, populated from every "name.<lang>" field already present except name.en (English always comes fresh from missalemeum) and re-emitted verbatim, sorted for deterministic output -- a third or fourth language added later survives a regeneration without this function changing again. CRITICAL 2: St Romanus was deleted, and St Eusebius (14 August) excluded, on a primary-source claim the primary source itself contradicts. The exclusion cited the calendarium's 9 August row as reading only "Vigilia, III classis.", no "Com." line -- checked against ONE of the three local Missal scans, "1962-06-23,...LT.pdf", an ELECTRONIC TRANSCRIPTION. The other two, PHOTOGRAPHIC scans of the actual 1962 Missale Romanum, both carry it: "missale-romanum-1962.pdf" calendarium, 9 August: "XVI d V 9 Vigilia, III classis, Commemoratio S. Romani Mart.", with the saint's own proper text elsewhere in the same scan ("Et fit commemoratio S. Romani Mar-") and its own back-of-book index ("Romani Mart., 9 augusti ... 621"). The transcription silently drops vigil commemorations generally (also missing there, present in both photographic scans: 7 August Donatus, 25 December Anastasia). 14 August's "St. Eusebius" is the identical shape (calendarium: "XI b XIX 14 Vigilia, II classis, Commemoratio S. Eusebii Conf.") and genuinely a DIFFERENT person from 16 December's "St. Eusebius, Ep. et Mart." (calendarium: "V XVII S. Eusebii Ep. et Mart., III classis.") -- a Confessor and a Bishop-and-Martyr, not the same saint duplicated. knownSpuriousComm (both entries) is removed outright; slugOverride gains "08-14/eusebius" -> "eusebius-confessor" so the two no longer collide by slug. Going forward: the photographic scans are the primary source; the electronic transcription is a convenience index only; where they disagree, the scan wins -- recorded in the generator's own comments, not just here. IMPORTANT 3+4: Thomas Becket (29 Dec) and Silvester (31 Dec) were silently promoted to class-4 by a hidden coupling. RG 68(d)/(e): "die 29 decembris, fit commemoratio S. Thomae Episcopi et Mart.; die 31 decembris, fit commemoratio S. Silvestri I Papae et Conf." -- both a bare "Commemoratio" with NO class of their own; the DAY they fall on (within the Nativity Octave) is II class, confirmed in the same calendarium row. refYearExplainsAbsence calls calendar.Compute and trusts a commemoration's own id-rank when the temporal day looks class-1/2-strong; after this task's own earlier fix promoted 26-31 December from class-4 to class-2 (RG 67/68), that trust flipped for these two from "not explained" to "explained" purely as a side effect of an unrelated temporal_ef.go change -- the generator's data inference reads the engine's own computed ranks, so a temporal_ef.go rank change can silently rewrite generated data. Fixed narrowly (6-31 December excluded from ever trusting the id-rank, citing RG 68(d)/(e) directly) and the coupling itself documented in refYearExplainsAbsence's own doc comment as a standing hazard for the next temporal_ef.go rank change, not just this one instance. Separately, the SAME function's doc comment overstated its own guarantee ("ANY class-1..4 saint would lose there") -- false for its Lent/Passiontide limb, where a III-class privileged feria does not beat a I- or II-class feast (RG 109(e) is privilege over an equal-or-lower class only) -- and the "commemoration id names the saint's TRUE rank" claim at the call site was falsified by its own worked example (St Blaise's id claims rank 4, and he is still correctly ruled RankCommemoration). Both rewritten to describe this as the rank-blind sampling heuristic it actually is, not a rubric evaluator. IMPORTANT 5: the Purification's own citation, strengthened. Three fixes to classOf's doc comment, no data change (the tag stays "lord", per round 1's own decision): the colitur cross-reference is removed (colitur bootstraps from lectio and was reading the same oracle a second time, not independent corroboration, and citing a sibling project's in-flight branch is not itself an argument); the rule that actually makes the occurrence pattern diagnostic is now named -- RG 91 entry 14 ("Festa Domini II classis") above entry 15 ("Dominicae II classis") above entry 16 ("Festa II classis... quae non [sunt Domini]"), each verified directly against the scan, not paraphrased; RG 120(b) is recorded as genuine primary-text counter-evidence ("Adhibetur color albus... b) B. Mariae Virg., etiam in benedictione et processione candelarum die 2 februarii" -- 2 February filed under the white-colour rule's OWN "B. Mariae Virg." heading, separate from 120(a)'s "Domini" heading), and RG 112(b) ("Officium, Missa aut commemoratio de dominica excludit commemorationem... de festo vel mysterio Domini, et vicissim") is cited as independently backing the empty commemoration list. A new committed fixture test replaces reliance on the report alone, since the deciding years (2 February on a Sunday) fall outside this repo's committed 2026-2027 oracle snapshot: TestPurificationBeatsFebruarySunday (internal/calendar/precedence_ef_repro_test.go), five independently fetched years. One of the years this reasoning is sometimes quoted against, 2036, is corrected in passing: 2 February 2036 is in fact a Saturday, not a Sunday (`date -d 2036-02-02 +%A`) -- checked here rather than repeated, 2042 used instead. Witnesses (internal/caldata/caldata_test.go): TestTridentineNamesPreservedAcrossRegeneration, TestTridentineRomanusAndEusebiusPresent (replaces TestTridentineNoSpuriousRomanus, whose own name asserted the now-corrected wrong claim). Pre-fix failures (captured against the committed pre-round-2 state, commit 50e3970): name.pl coverage = 0 entries, want >= 315 assumption-of-the-blessed-virgin-mary: name.pl = "", want the preserved Polish name romanus missing: the calendarium's photographic scans both carry "Commemoratio S. Romani Mart." on 9 August missing "eusebius-confessor" (08-14) internal/caldata/tridentine-calendar.ini regenerated from the ORIGINAL branch-point data (`git show 2386a45:...`), not from this session's own already-damaged intermediate file -- regenerating from an already-corrupted source would have preserved nothing, since the preservation mechanism can only preserve what is actually on disk when it runs. Verified directly (not merely re-tested): all 322 name.en/name.pl values byte-identical to the branch point; 15 rank fields and 2 class fields differ (the round-1 Lenten-rank and class-tag fixes, unchanged by this round); 5 new slugs added (agnes-secundo, boniface-martyr, eusebius-confessor, evaristus, theodore); 0 slugs removed.
| | * gen-sanctoral-ef: keep the Purification tagged lord -- the brief was wrong hereLukasz Kasprzak2026-08-123-21/+49
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Disagreement with the task brief, found and corrected before landing, not after: the brief's defect 7 named the Purification (2 February) as "wrongly tagged lord... a BVM feast", citing the calendarium's own title, "IN PURIFICATIONE B. MARIAE VIRG." That citation is accurate -- but the tag's actual job is not naming or colour categorisation, it exists solely to drive one occurrence rule ("a II-class feast of the Lord takes an occurring Sunday's place outright"), and on THAT question the title is not the decisive evidence. Checked directly against missalemeum (this data's own oracle, live, not archival): the Purification takes a II-class Sunday's place OUTRIGHT, commemorations EMPTY (2014-02-02, 2020-02-02, 2025-02-02, all fetched fresh) -- the exact "festum Domini" pattern. Control: the Nativity of the BVM (8 September, an undisputed ordinary Marian feast) on a Sunday (2019-09-08) shows the opposite shape, the Sunday observed and the feast merely commemorated. The Purification's occurrence behaviour does not match an ordinary BVM feast's. Independent corroboration, found while comparing lectio's output against colitur's (the sibling engine this task's brief points to): colitur's own git history shows the identical retag, made and then reversed within the same review cycle it landed in -- cab8b07 "retag the Purification... as BVM, not Lord" (the brief's own reading), followed by 7d3b5ec "follow the oracle on the Purification" (the reversal, on the same live evidence independently re-derived here). That commit records the calendarium-title counter-evidence too and calls it "a genuinely contested point... a different project could reasonably rule the other way" -- not a clean-cut error either direction, but the weight of evidence for THIS tag's actual purpose favours keeping it lord. most-holy-name-of-mary (the OTHER entry the brief named) is untouched by this reversal and stays retagged away from lord -- its own occurrence behaviour matches the ordinary-BVM pattern, not contested by either project. internal/caldata/tridentine-calendar.ini regenerated; only the Purification's class field changes back (empty -> lord), 6 civil days 2005-2050 (every year 2 February falls on a Sunday: 2014, 2020, 2025, 2031, 2042, 2048) revert to matching what the branch point (and colitur's own current state) already had -- net zero change to PUBLISHED output on this specific point relative to before this task started, despite the intermediate wrong-then-reverted state along the way.
| | * calendar, precedence_ef: two more RG 91 gaps exposed by defect 4Lukasz Kasprzak2026-08-123-4/+101
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Found during the mandated 2005-2050 before/after verification (not one of the seven, but caused by defect 4's own fix, so fixed in the same pass rather than left as a self-introduced regression). Neither is a hypothetical: both are live in the fixed calendar and both were individually confirmed via cmd/lectio-ef-dump before being written up as tests. 1. RG 91 entry 4 (Immaculate Conception, Assumption BVM) sits ABOVE entry 6 (Sundays of Advent/Lent/Passiontide) -- unlike an ORDINARY I-class feast (entry 11, e.g. St Joseph), the Immaculate Conception (8 December) is not impeded by an Advent Sunday at all. Before defect 4, Advent Sundays were wrongly II class, so this was accidentally right (I beats II outright, no tie reached); once Sundays became I class the tie-break mattered for the first time, and precedenceEF had no branch for it -- the Sunday wrongly won. 2. RG 91 entry 5 (Vigil & Octave day of the Nativity) sits above entry 6 the same way, and its own gap was worse than a wrong winner: the Vigil of Christmas (24 December) falling on Advent IV, once defect 4 made that a genuine I-class tie, sent the Vigil into transferIfImpededEF's forward walk -- which has no way to re-place a transfer crossing the Dec 31/Jan 1 boundary (celebrationDate re-resolves a fixed date using the YEAR OF THE DAY BEING QUERIED, so a walk landing in the following January can never match the query that produced it). The Vigil did not move to the wrong day; it vanished for the whole year, for every year 24 December is a Sunday (2006, 2017, 2023, 2028, 2034, 2045). Both fixed the same way as the existing II-class-feast-of-the-Lord bonus in precedenceEF (a one-line precedence adjustment keyed on slug), generalised into a single beatsClass1Sunday helper covering both RG 91 entries. A separate, unrelated bug surfaced by the SAME verification pass and fixed alongside it: transferIfImpededEF's destination check reused precedenceEF's tie-break BAND to decide "is this day I or II class", but band encodes a different question (which of two EQUAL-class candidates wins a tie) -- an ordinary, non-Sunday II-class temporal candidate YIELDS under defect 2's own fix (band 5), even though it is genuinely II class. A day within the Octave of the Nativity (26-31 Dec, RG 67) is exactly such a day, so band<=3 alone let a transfer wrongly land inside it (a real reproduction: "vigil-of-christmas" would have landed on 29 December 2006 instead of vanishing outright, caught while tracing the entry-5 bug above). Replaced with a direct class test (isHighClass), which is both correct and simpler -- it no longer needs the Sunday flag at all for this particular check. Witnesses (precedence_ef_repro_test.go): TestImmaculateConceptionBeatsAdventSunday, TestVigilOfChristmasSurvivesAdventSunday. Fail before this commit with: 2013-12-08 observed = "ef-advent-sunday-2" want immaculate-conception-of-the-blessed-virgin-mary (RG 91 entry 4 beats entry 6) 2006-12-24 observed = "ef-advent-sunday-4" want vigil-of-christmas (RG 91 entry 5 beats entry 6; must not vanish) (full set: 2013/2019/2024 for the first, 2006/2017/2023/2028 for the second)
| | * scripts/gen-sanctoral-ef: fix rank inference, dedup, and class tagging ↵Lukasz Kasprzak2026-08-123-384/+426
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (defect 7) Six root-cause fixes to the generator, all in scripts/gen-sanctoral-ef.go, then a full regeneration of internal/caldata/tridentine-calendar.ini (323 -> 325 entries) against live missalemeum data: 1. Rank misinferred as "commemoration". A saint never OBSERVED in any of the six reference years was unconditionally hardcoded to RankCommemoration. 15 III-class feasts, all falling 6 March - 5 April, were always demoted by Lent's own privileged ferias in every reference year -- a sampling artifact, not their true rank. Fixed properly, not by hardcoding the 15: the commemoration object's own id names the SAINT's true rank (idParts already extracted it; only the colour half was kept before). But trusting that rank unconditionally for every commemoration-only entry over-corrected: some saints (St Blaise, St Canute, and others) really are without an independent Mass in the 1960-reformed books, demoted even on an ordinary, unprivileged day -- live-confirmed against missalemeum, not inferred. refYearExplainsAbsence distinguishes the two: the id's rank is trusted only when every reference year's OWN temporal day (ignoring sanctoral data entirely) was already strong enough to explain the demotion -- I/II class, an Ember day, or a privileged Lent/Passiontide feria. A single unprivileged-day counter-example keeps RankCommemoration. 2. Two silent slug collisions. entries (the generator's global map) is keyed by slug alone; two different fixed dates whose English titles are identical ("St. Agnes" 21 Jan and 28 Jan; "St. Boniface" 5 June and 14 May) silently dropped the second one add() ever saw. Fixed at the dedup itself: a same-slug collision on a DIFFERENT date is now disambiguated (a small curated slugOverride for these two -- 28 January is the traditional "secundo" commemoration of the same saint; 14 May's Boniface is a different martyr from 5 June's Boniface of Mainz) rather than dropped. 3. Two early-exit bugs in harvestDate, both replaced with `continue`: returning on the FIRST reference year that showed an observed office discarded commemorations only visible in a LATER year (St Theodore, 9 November, missing only from 2025, the first year tried); the Christ-the-King skip used to abandon the whole date outright instead of only that one movable year (St Evaristus, 26 October, invisible because 2025 -- tried first -- happens to be the one reference year Christ the King lands there). 4. A new class of artifact the fix for (2) exposed rather than caused: a movable-transfer feast displayed on whatever civil date it actually landed on in one reference year (St Joseph pushed to 20 March by a Sunday of Lent; the Annunciation deferred past Holy Week; All Souls moved to the Monday; St Matthias shown on the 25th in a leap year) was being harvested as if it were a genuine fixed-date office for THAT transferred date. idHomeDate compares info.id's own embedded date against the mmdd being queried (live-confirmed: 2023-03-20's id is "sancti:03-19:1:w") and skips a mismatch. 5. classOf's substring matching, checked against the calendarium's own verbatim titles: "purification" was never a Lord check at all (calendarium "IN PURIFICATIONE B. MARIAE VIRG.", a BVM feast) and is removed; "holy name" alone matched both "Holy Name of Jesus" and "Most Holy Name of MARY" (calendarium "Sanctissimi Nominis Mariae") and is now conditioned on the title not also naming Mary; "baptism" is a new case -- "Commemoration of the Baptism of the Lord" (13 January) ends "of THE Lord", not "of OUR Lord", the only suffix classOf checked, so it was missing the marker entirely. 6. One curated exclusion, NOT a generator bug: missalemeum's own "St. Romanus" commemoration on 9 August has no calendarium support (the row there reads only "Vigilia, III classis.", no "Com." line) -- an upstream data quirk, recorded in knownSpuriousComm rather than silently reproduced. "St. Eusebius" on 14 August (already known, register M6) gets the same treatment for the same reason. Witnesses (internal/caldata/caldata_test.go): TestTridentineClassOfLord, TestTridentineLentRankNotCommemoration, TestTridentineGenuineCommemorationStaysCommemoration, TestTridentineNoMissingEntries, TestTridentineNoSpuriousRomanus, TestTridentineNoTransferArtifacts, plus TestTridentineLoads' own Purification class assertion corrected from its previous (wrong) "lord" expectation. All fail against the pre-fix ini with messages such as: purification-of-the-blessed-virgin-mary: class = "lord", want "" sts-felicitas-perpetua: rank = "commemoration", want class-3 (not commemoration) missing "theodore" (11-09) romanus present: the calendarium's 9 August row has no Com. line to support it See the report for the full set. internal/caldata/tridentine-calendar.ini is regenerated output (go run scripts/gen-sanctoral-ef.go against live missalemeum data), not hand-edited.
| | * test(ef): un-gate the oracle test now the seven defects are fixedLukasz Kasprzak2026-08-121-10/+0
| | | | | | | | | | | | | | | | | | | | | | | | | | | Remove the LECTIO_EF_ORACLE_STRICT gate added when the strengthened rank/colour assertions first landed. All seven defects are fixed as of the previous four commits; TestOracleEF now passes unconditionally as part of the normal go test ./... run, with its small, cited allow-list (four entries, none of them one of the seven) doing the only remaining filtering.
| | * precedence_ef: a II-class privileged feria yields to a feast (defect 2)Lukasz Kasprzak2026-08-123-22/+110
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | precedenceEF's equal-class tie-break only distinguished "ordinary III/IV-class feria yields" from "everything else wins" -- Sundays, named feasts, Lent/Passiontide ferias, AND II-class privileged ferias (the Ember days, the late-Advent 17-23 Dec ferias) were all bucketed into the same "wins its tie" branch. RG 91 disagrees at class 2: entry 15 (Sundays) sits ABOVE entry 16 (II-class feasts of the universal Church), so a Sunday wins -- but entry 16 sits ABOVE entry 18 (II-class ferias, including the Ember days), so those FERIAS yield instead, the opposite direction from a Sunday. St Matthew (21 September, II class) was losing to the September Ember Wednesday every time the two coincided; St Thomas (21 December, II class) was losing to an ordinary late-Advent feria the same way once the previous commit correctly promoted those ferias to II class. The fix distinguishes a II-class Sunday from a II-class feria using a Sunday flag that already existed on `candidate` (used by the OF path) but was never wired up for EF: temporal_ef.go's efCel always set Sunday: false, even on an actual Sunday. A new efSunday helper (efCel plus the flag) replaces the three efCel calls inside temporalEF's Sunday branch, and computeEF now propagates td.Sunday into the day's temporal candidate. precedence_ef_test.go's own pre-existing witness ("at equal class, the temporal office wins") encoded exactly the bug: a bare class-2 temporal candidate with no Sunday/season information, standing in for "the temporal office" in general. It is rewritten into two explicit cases (Sunday wins its tie; a privileged feria yields) plus the existing Lent/Passiontide-vs-ordinary III/IV-class case restated explicitly rather than left implicit. Witness (precedence_ef_repro_test.go): TestMatthewBeatsSeptemberEmberWednesday. Fails before this commit with: 2016-09-21 observed = "ef-september-ember-wed" want matthew (RG 91 entry 16 beats entry 18) 2022-09-21 observed = "ef-september-ember-wed" want matthew (RG 91 entry 16 beats entry 18) With this commit, all seven named defects are fixed: LECTIO_EF_ORACLE_STRICT=1 go test ./internal/calendar/... -run TestOracleEF passes (0 unallow-listed rank/colour mismatches over 730 days). The gate stays in place for this commit; a following commit removes it.
| | * calendar: RG 96 transfers must skip II-class days too (defect 1)Lukasz Kasprzak2026-08-122-12/+86
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | transferIfImpededEF's forward walk only skipped days whose temporal office was I class. RG 96 requires skipping to "the next following day that is not I or II class" -- II class also blocks. 2011: the Sacred Heart (Friday after the Corpus Christi octave) falls on 1 July and impedes the Precious Blood, also fixed on 1 July. The walk landed the Precious Blood on 2 July, displacing the Visitation (II class, fixed) outright, and never reached 3 July (an ordinary II-class Sunday) at all. Two changes were needed together, not one: 1. The walk's continuation threshold widens from "temporal band <= 2" to "<= 3", which is what actually captures every II-class temporal day (an ordinary Sunday, or a II-class named feast) as well as every I-class one -- band 3 is precedenceEF's own value for any non-Sunday-privileged II-class temporal candidate, unchanged by this commit. 2. A FIXED sanctoral II-class feast (the Visitation) has no temporal band at all -- the walk needs to also check whether some OTHER fixed celebration, class 1 or 2, already resolves onto the candidate day. computeEF now builds this check once (occupiedByRank, parameterised by which ranks count) and passes it in. Widening (1) alone is wrong on its own: a class-1 feast is NEVER actually impeded by a mere II-class day (I class always outranks II class outright, no tie exists) -- naively applying the wide "<=3" threshold to decide whether the ORIGINAL date is impeded, not just where to land afterwards, wrongly bumped unimpeded feasts landing on an ordinary Sunday (caught while testing this: All Saints, 1 Nov 2026, a Sunday that year, was wrongly pushed to 3 Nov). transferIfImpededEF now uses two different thresholds for two different questions -- class 1 only to decide IF a candidate is impeded at all, class 1 OR 2 to decide where an already-impeded one may land -- see its own doc comment for the full reasoning. Witness (precedence_ef_repro_test.go): TestTransferSkipsBothIAndIIClass. Fails before this commit with: 2011-07-02 observed = "precious-blood-of-our-lord-jesus-christ" want visitation-of-the-blessed-virgin-mary (RG 96: the Precious Blood must skip past it, not displace it) 2011-07-04 observed = "ef-time-after-pentecost-3-monday" want precious-blood-of-our-lord-jesus-christ (RG 96: first day that is neither I nor II class)
| | * temporal_ef: Sunday ranks, Rose Sundays, Holy Thursday whiteLukasz Kasprzak2026-08-123-18/+200
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Four fixes to internal/calendar/temporal_ef.go, all found by the strengthened oracle test (previous commit): 1. Sunday ranks (defect 4). The generic Sunday branch assigned class-2 to every Sunday except Advent I. RG 11-12 / RG 91 entry 6: every Sunday of Advent and every Sunday of Lent is I class (as are Passiontide's own two Sundays and Low Sunday, already correct via their named-feast cases). Fixes St Joseph wrongly taking a Sunday of Lent (defect 3, precedence_ef_repro_test.go's TestJosephYieldsToSundayOfLent) as a direct consequence: once Lent Sundays are I class, Joseph (also I class) no longer wins the tie outright and correctly transfers to the 20th via the existing RG 96 walk -- no separate code change was needed for defect 3. 2. Rose (defect 5). efColour had no Rose case at all; Gaudete (Advent III) and Laetare (Lent IV) now get Rose on that Sunday specifically (RG 131: rose vestments may be used "in Officio et Missa diei dominici tantum", for that Sunday's Office and Mass only), not the surrounding Sundays. 3. Holy Thursday's colour (defect 6). RG 128(b) names the Missa in Cena Domini as a whole-Mass exception to Passiontide's violet; RG 122 states the same fact affirmatively, in the White section itself. Good Friday and Holy Saturday, either side, are unchanged (still violet -- their own black/no-colour treatment is a separate, unmodelled gap, noted in precedence_ef.go's own doc comments). 4. Beyond the seven, found by the same strengthened test and fixed for the same RG 91 entry 18 reason defect 2 (next commit) relies on: the Ember days of Lent had no case in efEmberSlug at all (only September and Advent did), so they fell through to the ordinary III-class Lenten-feria rank instead of the II class RG 91 entry 18 requires. The late-Advent ferias (17-23 Dec, RG 91 entry 18) and the days within the Octave of the Nativity (26-31 Dec, RG 67-68) had no elevation at all, defaulting to III/IV class. All three are one-line, unambiguous, primary-cited additions to the same rank logic already being touched here -- left unfixed, the strengthened oracle test could only reach green by allow-listing them as if they were defensible divergences, which they are not. Witnesses (temporal_ef_test.go): TestTemporalEFSundayRanks, TestTemporalEFRoseSundays, TestTemporalEFHolyThursdayColour, TestTemporalEFEmberDayRanks. All fail before this commit; see the report for the exact pre-fix failure messages.
| | * test(ef): strengthen the oracle test to assert rank and colourLukasz Kasprzak2026-08-123-2821/+5231
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | internal/calendar/oracle_ef_test.go asserted Season only. lectio's own EF oracle test comment said as much ("rank/colour are reported informationally"), which is exactly why several precedence/colour defects in precedence_ef.go and temporal_ef.go shipped without ever failing a test: the suite was green while the observed office's own rank and liturgical colour could be wrong. Rebuild the oracle from the committed missalemeum snapshot (sources/snapshot.tar.gz, missalemeum/en/YYYY-MM-DD.json, 2026-01-01 .. 2027-12-31, 730 days) instead of a live 2025-2026 fetch, via a rewritten scripts/build-oracle-ef.sh -- offline, reproducible, and correctly separating info.rank/info.colors from info.id (whose embedded rank is the rank of the propers REUSED that day, not the day's own rank -- e.g. 2026-01-02 is a class-4 feria carrying id "sancti:01-01:1:w" because it reuses the Circumcision's propers). info.colors is an array (14 of 730 days carry two values -- Gaudete/ Laetare "pv", Palm Sunday "rv", Good Friday "bv", Holy Saturday "vw"), so the new Colour assertion is membership, not equality. The strengthened assertions immediately expose several real defects (rank mismatches on every Advent/Lent Sunday, the Ember days, the late-Advent and Christmas-octave ferias, and more) -- that is the point, this is the regression net subsequent commits fix against. Since the repo's convention is go test ./... green at every commit, TestOracleEF is gated behind LECTIO_EF_ORACLE_STRICT=1 for now rather than landed red; a later commit removes the gate once the fixes are in. Season alone stays green throughout (unchanged, always was). A small, cited allow-list (efAllowList) is included from this commit: genuine, defensible divergences unrelated to the fixes ahead of it -- RG 91 entry 27's un-built BVM Saturday Office, the pre-existing 6-13 January Christmastide/time-after-Epiphany season-boundary divergence, missalemeum's own RG 33 gap on a Sunday 9 August, and one collision (St Joseph vs the Friday of Passion Week, 2027) left explicitly unresolved even by the sibling project's much deeper primary-source pass. None of the four is one of the seven defects this branch fixes.
| * cmd(lectio-ef-dump): new EF calendar dumper for colitur's differential oracleLukasz Kasprzak2026-08-121-0/+106
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Prints one line per day, sorted ascending, for a civil-year range: date, weekday, season, week, observed slug, rank, colour, then zero or more +slug tokens for the day's other (losing) candidates. The line format matches colitur's `colitur day` output field-for-field so the two streams diff directly; every column carries lectio's own vocabulary (season names, slugs, rank/colour spellings) with no translation toward colitur's — that mapping belongs to the differential comparator, not this dumper. Uses calendar.Compute with Selection{Form: "old"} over the embedded tridentine layer (caldata.Tridentine()), mirroring the setup already used by oracle_ef_test.go. Lives in cmd/ because internal/calendar cannot be imported outside this module; colitur's build is untouched. Note for the comparator: lectio has no RG 111 commemoration-admission logic, so the trailing +slug tokens are the day's losing candidates, not admitted commemorations.
| * calendar/readings: report Sunday as its own display rank, not solemnityLukasz Kasprzak2026-08-057-6/+103
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The Ordinary Form's Table of Liturgical Days treats Sunday as its own category, never a solemnity. temporal.go's sundayDay() already marks these days distinctly from named solemnities (Class stays unset, unlike solemn()'s ClassLord); internal/readings/offline.go now reads that existing signal to relabel the REPORTED rank to "sunday" for ordinary and privileged-season Sundays alike, leaving Celebration.Rank, ofRankOrder and all precedence untouched. Named solemnities landing on a Sunday (Easter, Pentecost, ...) and feasts of the Lord (Holy Family) keep reporting their own rank. The 1962 form is untouched. Added calendar.RankSunday (display-only, deliberately excluded from ofRankOrder), the i18n Sunday/niedziela words, and a test pinning the exact dates from the original bug report.
| * mobile: fix the documented gomobile bind command so it reproduces the ↵Lukasz Kasprzak2026-08-051-1/+8
| | | | | | | | | | | | | | | | | | | | | | | | shipped .aar The comment omitted -javapkg, the second -target ABI and -androidapi. A clean clone following it got a .aar whose classes sit under go.mobile.gojni instead of xyz.labunix.dlectio.engine.mobile, carries only arm64-v8a, and declares no minSdkVersion match to the app's 26 -- the app cannot import the result. Verified by rebuilding the binding with the corrected command and confirming the artifact's ABIs, package and minSdkVersion against the shipped one.
| * readings: PartIDs(new) stops declaring aklamacja, which the engine never emitsLukasz Kasprzak2026-08-053-13/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | caldata.go:42 parses only first/psalm/second/gospel out of the lectionary data, so no OF reading ever carries Part == "acclamation". PartIDs("new") listed aklamacja anyway, so the app built a checkbox from it that filters an ID that never appears -- a dead control, same defect class the app previously shipped for the whole 1962 form. ofPartOrder stays the full five-ID set: it also drives render.LocalizeHeading's label matching, where a scraped heading can still read "Aklamacja" even though this engine's own readings never produce that section. PartIDs now draws from a new, narrower ofEmittedPartOrder instead. Rewrote TestPartLabelsMatchesWhatTheEngineEmits's OF half: it compared PartLabels("of") to a hand-copied duplicate of ofPartOrder, asserting a declaration against itself, which cannot fail for this class of bug. It now sweeps Days over calendar year 2026 and asserts PartLabels("of") matches the observed part-ID set exactly (0.5s). Confirmed red against the pre-fix code, green after.
| * mobile: strengthen the PartLabels fallback test and count boundsLukasz Kasprzak2026-08-042-4/+20
| |
| * i18n: pin the Polish part labels; cross-reference the part-ID ordersLukasz Kasprzak2026-08-043-0/+48
| |
| * mobile: add PartLabels so the app stops hardcoding part IDsLukasz Kasprzak2026-08-032-0/+76
| |
| * mobile: add Days, a text-free week projection for the calendarLukasz Kasprzak2026-08-032-0/+155
| | | | | | | | | | A week through Days benchmarks at ~9-10ms/op, versus ~23ms for seven full days through Day.
| * mobile: return the day's rank and its localised labelLukasz Kasprzak2026-08-032-9/+56
| |