diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-12 14:50:34 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-12 14:50:34 +0200 |
| commit | e122fa4368e156b9c90c128a8daad9545b22ed11 (patch) | |
| tree | a652429898a4ee94908ad1a96b3bf4d7d5ed1fe8 /internal/caldata/caldata_test.go | |
| parent | 50e39702bad835962b6e9c04253572e5b48a951f (diff) | |
| download | lectio-e122fa4368e156b9c90c128a8daad9545b22ed11.tar.gz lectio-e122fa4368e156b9c90c128a8daad9545b22ed11.zip | |
gen-sanctoral-ef, caldata: fix round 2 -- review found five real problems
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.
Diffstat (limited to 'internal/caldata/caldata_test.go')
| -rw-r--r-- | internal/caldata/caldata_test.go | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/internal/caldata/caldata_test.go b/internal/caldata/caldata_test.go index a9bc860..2ba052d 100644 --- a/internal/caldata/caldata_test.go +++ b/internal/caldata/caldata_test.go @@ -216,18 +216,49 @@ func TestTridentineNoMissingEntries(t *testing.T) { } } -// TestTridentineNoSpuriousRomanus: the calendarium's 9 August row reads only -// "Vigilia, III classis.", with no "Com." line -- missalemeum's own "St. -// Romanus" commemoration that day has no calendarium support and is a -// genuine upstream data quirk (the same standard already applied to "St. -// Eusebius" on 14 August, also excluded). -func TestTridentineNoSpuriousRomanus(t *testing.T) { +// TestTridentineRomanusAndEusebiusPresent: CORRECTED after review found the +// opposite claim resting on an incomplete primary-source check. An earlier +// version of this test (and of scripts/gen-sanctoral-ef.go's +// knownSpuriousComm) asserted Romanus ABSENT, on the strength of ONE of the +// three local Missal scans -- "1962-06-23,…LT.pdf", an ELECTRONIC +// TRANSCRIPTION that silently drops vigil commemorations generally (also +// missing: 7 August Donatus, 25 December Anastasia, both present elsewhere). +// The other two, PHOTOGRAPHIC scans of the actual 1962 Missale Romanum, both +// carry it: "missale-romanum-1962.pdf" calendarium, 9 August row: "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"). +// Where the scans and the transcription disagree, the scans win -- see +// gen-sanctoral-ef.go's own primary-source note, same rule recorded there so +// it is not lost a second time. +// +// 14 August's "St. Eusebius" is the identical shape (calendarium: "XI b XIX +// 14 Vigilia, II classis, Commemoratio S. Eusebii Conf.") and 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 moved or duplicated. missalemeum gives both +// the same bare English title, so they collide by slug; slugOverride +// disambiguates rather than either being dropped. +func TestTridentineRomanusAndEusebiusPresent(t *testing.T) { l := Tridentine() - if _, ok := l.Cels["romanus"]; ok { - t.Error("romanus present: the calendarium's 9 August row has no Com. line to support it") + if rc, ok := l.Cels["romanus"]; !ok { + t.Error("romanus missing: the calendarium's photographic scans both carry \"Commemoratio S. Romani Mart.\" on 9 August") + } else if rc.Fields["date"] != "08-09" { + t.Errorf("romanus: date = %q, want 08-09", rc.Fields["date"]) } - if rc, ok := l.Cels["eusebius"]; ok && rc.Fields["date"] != "12-16" { - t.Errorf("eusebius: date = %q, want 12-16 (14 August's Eusebius has no calendarium support)", rc.Fields["date"]) + want := map[string]string{ + "eusebius-confessor": "08-14", // "S. Eusebii Conf." -- a Confessor + "eusebius": "12-16", // "S. Eusebii Ep. et Mart." -- a Bishop and Martyr, a different person + } + for slug, date := range want { + rc, ok := l.Cels[slug] + if !ok { + t.Errorf("missing %q (%s)", slug, date) + continue + } + if rc.Fields["date"] != date { + t.Errorf("%s: date = %q, want %q", slug, rc.Fields["date"], date) + } } } @@ -252,3 +283,46 @@ func TestTridentineNoTransferArtifacts(t *testing.T) { } } } + +// TestTridentineNamesPreservedAcrossRegeneration is the coverage guard a +// regeneration silently destroying a whole language's names needed and did +// not have: an earlier version of scripts/gen-sanctoral-ef.go's main() +// preserved existing name.la values across a regeneration (missalemeum +// supplies English only) but had no equivalent for name.pl -- and, because +// the bootstrapped file has in fact never carried a name.la value, that +// mechanism looked correct while doing nothing at all. A regeneration +// deleted all 322 Polish names outright (name.pl count 322 -> 0), silently: +// no test here asserted anything about a name.* field, and +// `len(l.Cels) < 250` (TestTridentineLoads) does not notice a field going +// missing within entries that still exist. `naming.CelebrationName`'s own +// name[lang] -> name.en fallback (internal/naming/naming.go) then quietly +// substituted English for Polish on every EF display in that language, +// reaching mobile.Day(date, "ef", version, "pl") -- a shipped dlectio entry +// point -- with no error anywhere in the chain. +// +// Checks both a broad coverage floor (not exactly 322: a handful of entries +// added by this same task's own fixes -- St Agnes secundo, St Boniface +// Martyr, St Evaristus, St Theodore, St Romanus, St Eusebius Confessor -- +// never had a curated Polish name to preserve in the first place, so 322 is +// not achievable) and one specific, checkable value (the coordinator's own +// example) so a coverage-only guard cannot itself be satisfied by silently +// wrong values. +func TestTridentineNamesPreservedAcrossRegeneration(t *testing.T) { + l := Tridentine() + n := 0 + for _, rc := range l.Cels { + if rc.Fields["name.pl"] != "" { + n++ + } + } + if n < 315 { + t.Errorf("name.pl coverage = %d entries, want >= 315 (was 322 before any of this task's fixes; a regeneration must preserve it, not merely not-crash)", n) + } + rc, ok := l.Cels["assumption-of-the-blessed-virgin-mary"] + if !ok { + t.Fatal("missing assumption-of-the-blessed-virgin-mary") + } + if got := rc.Fields["name.pl"]; got != "Wniebowzięcie N. M. P." { + t.Errorf("assumption-of-the-blessed-virgin-mary: name.pl = %q, want the preserved Polish name", got) + } +} |
