aboutsummaryrefslogtreecommitdiff
path: root/lib/rites/rite_ef/temporal_ef.mli
Commit message (Collapse)AuthorAgeFilesLines
* feat(ef): implement the calendarium's bissextile February shiftLukasz Kasprzak2026-08-221-0/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The Missale Romanum's calendarium footnote for February (LT.txt:5011-5014, scan-corroborated scan2.txt:3050-3058): in a leap year the sixth kalends of March (24 February) is doubled rather than a 29th day appended, so St Matthias moves 24->25 February and St Gabriel of Our Lady of Sorrows 27->28, with 24 February itself carrying no fixed office that year. data/ef/expected-divergences-lms.sexp entry L3 tracked this as an open gap. Implemented as the rubric's own general mechanism (every fixed entry from 24 through 28 February shifts one civil day later in a leap year), not as "move these two named saints": the two readings are indistinguishable on shipped data (nothing else is fixed in that window) and diverge only for a future --overlay entry in the same range, which the mechanism reading covers correctly and a two-saints special case would not. This project has already been bitten once (RG 16(a)) by a rule implemented against shipped data's coincidental shape rather than the rubric itself. Kernel stays rite-agnostic: Rite.t gains a fixed_key field (Date.t -> (int * int) option), the same seam easter already establishes, read only by Layer.on_date's FIXED half -- the movable half (Easter_offset/Nth_weekday) is untouched. Default is the identity mapping, an optional argument on on_date, so every existing caller and every rite that supplies nothing is byte-identical to before this field existed. Date.is_leap is exposed in date.mli (already existed in date.ml) so the rite reads the kernel's own single-sourced leap-year definition. The EF implementation lives in Rite_ef.Temporal_ef.bissextile_fixed_key, fully cited, wired into Rite_ef.context. Blast radius, measured over the full 1583-9999 domain (Calendar.year run twice per civil year, real fixed_key vs identity, every day diffed): all 2,041 leap years in the domain show a visible change for each saint; 6,983 individual liturgical days change total, zero unclassified, across four shapes (Matthias vacates 24 Feb in 1,803 years / occupies 25 Feb in 1,811; Gabriel vacates 27 Feb in 1,699 / occupies 28 Feb in 1,670). L3's own prior estimate (1,650 years, observed-outright only) is confirmed close on the same definition (1,677 measured); the broader observed-or- commemorated count is higher, not lower, showing the narrow estimate undercounted visible impact rather than overcounting it. The lectio differential (2005-2050 fixture) gains a new cited entry, C40 in data/ef/expected-divergences.sexp: lectio implements no such shift, so every leap year in its window now diverges on the two shifted days (21 rows, not the naive 44 -- the comparator never compares commemorations, so a side where the shifted saint has zero comparator-visible footprint on both engines produces no row). The LMS Ordo's 2023-2024 fixture -- the window L3 was originally found in -- now matches on the Creed comparison; its formulary-override bucket count is corrected 182->181 (24 February leaves the counted Proper population, becoming Own_slug-sourced). The missalemeum oracle fixtures (2026-2027, 2038, 2035) cover no leap year and are unaffected. L3 is closed: converted from an active allow-list record to a prose closure paragraph (L1's own precedent), citation preserved verbatim, fix and measured blast radius recorded. The id-list assertion narrows to [L4] alone, and the now-dead "2024-02-24" -> "L3" date mapping is removed. Six golden values pinned across four new test cases: Matthias in a leap year (both the vacated and occupied sides) and a common-year control; Gabriel likewise, deliberately choosing a leap year where he is admitted only as an ordinary commemoration rather than winning outright, a different shape from Matthias's. Mutation-tested: forcing fixed_key back to identity reddens exactly five test cases -- the differential's Layer C count-pin (C40 drops to 0 actual vs 21 expected), the LMS Ordo's Creed and formulary-bucket checks, and both new golden pins -- confirming the tests actually exercise the fix. Reverted; dune test, the exhaustive sweep, and make check are all green.
* temporal(ef): Holy Name of Jesus, RG 17(a) -- fallback + Lord subjectLukasz Kasprzak2026-08-131-0/+11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 17(a): "festum Ss.mi Nominis Iesu, celebrandum dominica quae occurrit a die 2 ad 5 ianuarii (secus die 2 ianuarii)" -- both photographic scans, confirmed on the calendarium's own January table and the Mass propers' own heading. Two defects closed together, since they interact through RG 91 entry 14/RG 16(a): 1. The Sunday shape (2-5 January) now tags subject = Lord, matching RG 91 entry 14 ("Festa Domini II classis") -- previously subject = Temporal, the same defect shape Holy Family had before it. 2. The fallback (RG 17(a)'s own "secus die 2 ianuarii", the calendarium's "vel, ea deficiente, die 2 ianuarii") is now built: 2 January carries the feast whenever no Sunday falls 2-5 January that year. Before this fix colitur emitted no Holy Name office at all in such a year -- a real II-class feast simply missing, on 3,619 of 8,417 years in the domain (43%; 20 of the 46 years 2005-2050, independently re-derived against `date -d`). Both shapes band identically at RG 91 entry 14's MOVABLE half (Precedence_ef.entry_14_movable_band) -- one feast, not two differently classified ones, per the Mass propers' own single heading covering both dates. No live collision exists in the current sanctoral data (nothing fixed-date falls 2-5 January besides a Commemoration_only entry on 5 Jan), so the RG 16(a)/RG 112(a) interaction is proved with synthetic precedence-level fixtures mirroring Holy Family's own precedent, not a live-data regression. One asymmetry the synthetic tests found and kept honest rather than forced: a losing Holy-Name-Sunday is privileged (RG 109(a), "of a Sunday") and survives RG 111(a)'s cap; a losing Holy-Name-fallback is not (2 January is not a Sunday, and no other RG 109(a)-(f) category applies to it), so it gets no commemoration at all if ever outranked -- both individually correct readings of RG 109/111's closed lists. Golden pins follow the brief's own vacuity warning: the Sunday shape already emitted the right slug/rank/colour before this fix (an ordinary Sunday and Holy Name coincide on those fields), so its pin asserts subject explicitly rather than pinning the whole line uncritically; the fallback pin (2029-01-02) is the one with teeth against the larger defect, reddening on slug/rank/subject together if reverted. Mutation-tested: each half of the fix reverted separately reddens exactly its own tests (Sunday subject: the dedicated unit test, the golden pin's subject field, one precedence end-to-end test; fallback: the fallback unit/anchor/golden tests, the new C16 differential count, and both shapes of the precedence end-to-end tests) and nothing else. Adds data/ef/expected-divergences.sexp's C16 (lectio has no fallback for this window at all) -- the lectio differential's own count, independently re-derived against `date -d` for the fixture's 2005-2050 span, not transcribed from the domain-wide figure. The missalemeum oracle window (2026-2027) exercises only the Sunday shape and needed no new entry: subject is not one of its compared fields, and both years' rows already corroborate the Sunday-shape ranking (missalemeum's own 2026-01-04 and 2027-01-03 rows: rank 2, white, title "Holy Name of Jesus").
* temporal(ef): the Holy Family, first Sunday after Epiphany (RG 17(b))Lukasz Kasprzak2026-08-131-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | RG 17(b), verified against both photographic scans (missale-romanum- 1962.pdf and "Missale Romanum 1962_text.pdf" -- the electronic transcription carries the same paragraph, so this one is not itself a transcription-vs-scan divergence): the Holy Family of Jesus, Mary and Joseph is celebrated on the first Sunday after Epiphany, II class, EVERY year, taking the Sunday's own place "cum omnibus iuribus et privilegiis" -- the same formula RG 16(a) already uses. The slug, rank and colour temporal_ef.ml already computed for that Sunday (ef-time-after-epiphany-sunday-1, Class2, white) turn out to be exactly right by coincidence -- an ordinary, unnamed Sunday and Holy Family share both. The only field that was silently wrong is subject: always Temporal before this, when RG 91 entry 14 ("Festa Domini II classis, primum mobilia, deinde fixa") calls Holy Family a movable Feast of the Lord. temporal's build now takes an optional ~subject, applied only on Holy Family's own date -- every other Sunday, including the still-unbuilt Holy Name of Jesus (RG 17(a)), is unaffected. RG 17(b)'s window (7-13 January) can never be empty of a Sunday -- sunday_on_or_before(6 Jan) + 7 always lands in [7, 13] regardless of 6 January's weekday -- unlike RG 17(a)'s Holy Name (2-5 January, CAN be empty), whose calendarium entry carries an explicit "vel ea deficiente, die 2 ianuarii" fallback right next to Holy Family's own, fallback-free one. No fallback needed or built. Added to anchors (holy_family_sunday is independently computed, not routed through named -- see temporal_ef.ml's own comment on why) and to its own dedicated anchor/erosion test in test_temporal_ef.ml, kept separate from the generic named-days coverage test since this genuinely isn't one of named's own outputs. Does not yet touch precedence: band still has no notion of a movable Class2 Lord feast (entry 14 gates on sanctoral origin only), so on the seven years 13 January is itself Holy Family's date (2008, 2013, 2019, 2030, 2036, 2041, 2047), the fixed Commemoration of the Baptism of the Lord still wins the day exactly as before this commit -- the next commit fixes the ordering RG 91 entry 14's own text states ("primum mobilia, deinde fixa").
* rite(ef): fix duplicate slugs and omitted weeks in the temporal cycleLukasz Kasprzak2026-08-111-3/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Two correctness bugs in Temporal_ef, both only visible across many years, not a single point assertion: 1. Duplicate slugs within one liturgical year. Christmastide has no numbered weeks, so the ferial fallback's <season>-<week>-<weekday> scheme collapsed every feria in it to literal week "0". Since colitur's Christmastide runs 25 Dec - 13 Jan (RG 72-73, a deliberate divergence from lectio), the same weekday recurs across that span and the keys collided (e.g. ef-christmas-0-saturday on three different dates). Fixed with a dedicated christmastide_feria_slug that splits the span into four sub-stretches, prioritising compatibility with lectio's own keys wherever lectio has one: - 26-28 Dec keeps lectio's existing ef-christmas-0-<weekday>. - 2-5 Jan becomes ef-christmas-1-<weekday> -- lectio collapses this indistinguishably into the same key as the stretch above, so there is nothing to preserve; a colitur-only lectionary gap. - 7-13 Jan splits at the actual first-Sunday-after-Epiphany origin: on/after it, this is genuinely week 1 of Time after Epiphany and takes lectio's own ef-time-after-epiphany-1-<weekday> (which also can't collide with that season's own later week-1 ferias, since it's the same computation). Before it (0-6 days, whenever Epiphany doesn't fall on a Saturday), a first attempt at labelling this "week 1" too, matching a literal reading of lectio's behaviour, was verified empirically (a throwaway sweep of the full 1583..9998 domain) to reproduce duplicates in most years -- so this remainder is its own ef-christmas-2-<weekday>, a further colitur-only gap. Verified with the same throwaway sweep: zero duplicate slugs across 1583..9998 after the fix. 2. named's week field was set by hand on some branches (Passion/Palm Sunday, Easter, Low Sunday, Pentecost and its Vigil, Christ the King) and left at None on others (Ascension and its Vigil, Corpus Christi, Sacred Heart) even though all of them sit inside a numbered season run. named no longer carries a week at all -- temporal now calls week itself for every day, named or not, so "a named day inside a run carries that run's week" holds by construction rather than by remembering to set it on each branch. temporal.mli's week field doc is reworded to state the actual rule. Covering tests: point assertions for all four Christmastide sub-stretches; a QCheck property scanning random years for any duplicate slug within a liturgical year (excluding the deliberate resumed-Sunday reuse); point assertions for the four previously-None days now carrying their week (first to fail without the fix: Ascension Vigil, expected Some 6, got None); a QCheck property asserting temporal's week equals week for every day of the year, replacing a prior property whose fallback made it structurally incapable of detecting an omitted week. Also: cite RG 91 e18 for the September/Advent Ember days matching lectio and flag the Lent/Whitsun Ember and Rogation slugs as colitur-only lectionary gaps inline, matching the existing Nativity-vigil/octave-day convention; cite RG 117/123/127/128/131 for season colours and Gaudete/Laetare rose; drop the unreachable Passiontide arm from the Sunday-rank match (Passiontide has only two Sundays and both are already named above, so no Passiontide Sunday ever reaches that fallback).
* rite(ef): ferias, Ember days, Rogations and the temporal entry pointLukasz Kasprzak2026-08-111-0/+5
| | | | | | | | | | | | | | | | | | | | Ferial ranks per RG 91: I class in Holy Week and the privileged octaves (entries 7, 10), II class for Advent 17-23 and the Ember days (entry 18), III class for Advent to 16 December and Lent/Passiontide (entries 22, 25), IV class per annum (entry 28). Two further divergences from lectio, both from the table: Advent 17-23 are II class, and the Lenten Ember days are II class rather than ordinary Lenten ferias. Rogations (RG 80/87) exist at all, which lectio does not compute. Gaudete and Laetare are rose. Two corrections against the primary source beyond the task brief's draft. Entry 7 (verified against the Latin: "feria IV cinerum et II, III et IV Hebdomadae sanctae") covers only Ash Wednesday and Monday-Wednesday of Holy Week; Thursday-Saturday are the Sacred Triduum, entry 2, cited separately. Rogation Monday and Tuesday keep the ordinary ferial rank of their season (RG 88: "de Litaniis minoribus nihil fit in Officio") rather than a fixed class, since no RG 91 entry ranks them specially. A module-type constraint proves Temporal_ef satisfies the kernel RITE contract.
* rite(ef): Sunday slugs, week numbering and the resumed-Sunday tailLukasz Kasprzak2026-08-111-0/+12
| | | | | | | | Week origins are Sundays, so week numbers are constant Sunday-to-Saturday; the origin is season-specific, which is why Validate must not assume a run starts at 1. When Easter is early the surplus Sundays after Pentecost resume the Sundays after Epiphany that Septuagesima cut short, and the last Sunday before Advent always keeps the 24th (Last) Mass.
* rite(ef): named temporal days, vigils and the Nativity octaveLukasz Kasprzak2026-08-111-0/+8
| | | | | | | | | | The I-class feasts of the Lord (RG 91 entries 1-3), the Nativity, Ascension and Pentecost vigils (RG 28-34), and the days within the Octave of the Nativity (RG 64-70). Christ the King is the last Sunday of October per the 1960 calendar, not the OF's last Sunday before Advent. Rogation Wednesday coincides with the Ascension vigil; with no precedence framework until Plan 3, temporal emits the higher-ranked vigil.
* rite(ef): season boundaries per RG 71-77Lukasz Kasprzak2026-08-111-0/+12
Christmas Time runs to 13 January inclusive (RG 72-73) and time after Epiphany opens on 14 January (RG 77), diverging from lectio, which starts time-after-epiphany at 6 January. Holy Saturday stays in Passiontide: the Easter Vigil is a night Mass, and a per-day calendar assigns a date by the season governing its day-hours.