aboutsummaryrefslogtreecommitdiff
path: root/scripts/gen-sanctoral-ef.go
Commit message (Collapse)AuthorAgeFilesLines
* fix(ef): three saints with proper Masses had no readings at allLukasz Kasprzak2026-08-181-0/+12
| | | | | | | | | | | | | | 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-181-0/+52
| | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* fix(ef): twelve RG 124 colours -- missalemeum has the rule invertedLukasz Kasprzak2026-08-181-0/+39
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* feat(gen): teach the EF generator to preserve the Missal correctionsLukasz Kasprzak2026-08-181-5/+102
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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-181-0/+16
| | | | | | | | | | | | | | | | | | | 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.
* gen-sanctoral-ef, caldata: fix round 3 -- guard coverage, rank pins, name ↵Lukasz Kasprzak2026-08-121-22/+79
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* gen-sanctoral-ef, caldata: fix round 2 -- review found five real problemsLukasz Kasprzak2026-08-121-84/+180
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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-121-7/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* scripts/gen-sanctoral-ef: fix rank inference, dedup, and class tagging ↵Lukasz Kasprzak2026-08-121-32/+236
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (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.
* feat: complete OF+EF calendar coverage (movable feasts, vigils, ember days, ↵Lukasz Kasprzak2026-07-281-3/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | transfers) Ordinary Form: - Add the movable Marian memorials that have no fixed date: Mary, Mother of the Church (Monday after Pentecost) and the Immaculate Heart (Saturday after the Sacred Heart), computed in computeOF. - General Norms 60: two coinciding obligatory memorials both become optional and the ferial is observed -- except Mary, Mother of the Church, which keeps precedence per its 2018 decree. Extraordinary Form: - Capture fixed-date vigils in the sanctoral harvest (Christmas, the Nativity of St John the Baptist, Sts Peter & Paul, St Lawrence, the Assumption, All Saints, the Immaculate Conception) -- previously filtered out. - temporalEF: the movable vigils of the Ascension (I class eve) and Pentecost (Whitsun Eve), and the September/Advent Ember days (II class violet ferias). - transferIfImpededEF: the Annunciation transfers past Holy Week/the Easter octave to the Monday after Low Sunday; All Souls moves to Nov 3 when Nov 2 is a Sunday. - genlect harvests proper Masses for the new Ember/vigil days. Adds TestEFCoverage + TestOFMovableMemorials. Bumps to 0.39.0. Verified per-day: OF 0 real errors vs calapi (2026-2028, 100% correct-observed); EF 0 real errors vs missalemeum (2025-2027), residual = deep-tail vigil-occurrence and St Joseph Passiontide-transfer edges (~1-2 days/yr, documented).
* feat(ef): full 1962 universal sanctoral (16 -> 317 celebrations)Lukasz Kasprzak2026-07-281-0/+402
Generate internal/caldata/tridentine-calendar.ini from missalemeum's per-date proper API (Divinum Officium 1962 data) via scripts/gen-sanctoral-ef.go: each fixed date's observed saint with rank, colour, English name and proper Epistle/Gospel citations, plus sancti commemorations. Multiple reference years are tried per date so a saint occulted by a Sunday in one year is still captured observed in another; saints never observed are ranked commemoration. Feasts of the Lord are marked class=lord. Latin names hand-curated (missalemeum has none). Adds TestTridentineLoads, credits missalemeum in NOTICE, bumps to 0.38.0.