| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(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.
|
| |
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
| |
Per the review, the apostle title was split ("św. X, apostoła" vs
", Apostoła") and the evangelist title too (Mark/Matthew already
"Ewangelisty", John/Luke lowercase). Standardise both high author-ranks
to uppercase -- all apostles "Apostoła"/"Apostołów", all four evangelists
"Ewangelisty" -- matching the entries that were already capitalised. The
functional titles (biskupa, prezbitera, męczennika, doktora, dziewicy...)
stay lowercase, as they consistently were.
|
| |
|
|
|
|
|
|
|
|
|
| |
The universal [saints-philip-and-james-apostles] entry carried
name.pl = "Najświętszej Maryi Panny, Królowej Polski" -- Our Lady Queen
of Poland, the Polish NATIONAL feast that supersedes Philip & James on
that date, pasted in during the pl backfill instead of translating the
universal celebration. name.la and the readings correctly say Philip &
James. Set name.pl = "świętych Apostołów Filipa i Jakuba" (matching the
"świętych Apostołów Piotra i Pawła" style). Scanned the rest of both
universal calendars for other national-feast contamination -- none.
|
| |
|
|
|
|
|
|
|
|
|
| |
The exported month calendar's title showed the terse dropdown word
("August 2026 — traditional"). Spell the form out: "traditional roman
calendar" / "novus ordo calendar". Add dedicated i18n labels
CalModern/CalTraditional (translatable like the rest of the chrome; pl =
"kalendarz Novus Ordo" / "tradycyjny kalendarz rzymski") rather than
overloading the short OptModern/OptTraditional the settings dropdown uses.
Bump version to 0.45.1.
|
| |
|
|
|
|
|
|
| |
The version constant sat at 0.44.0 while 44 commits landed on top of it:
the engine-flawlessness pass, the localization + bible-corpora-split epic
(any-language day/saint names, embedded-chrome-as-data, EF Polish
sanctoral 322/322), the web UI rework, the EF Christmas-ferial name fix,
and the cli test-config isolation. Mark the release as 0.45.0.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The ref/rand cli tests assume English book abbreviations ("Jn 3:16"), but
with no LECTIO_CONFIG set they read the developer's real user config. On a
machine whose config has ui_language = pl (sigla_style = auto -> Polish
dialect), "Jn" is not a valid abbreviation and TestRefSingle,
TestRefEnglishDialect, TestRefRejectsPolishAbbrevInEnglish, TestRefCompare
and TestRandVerse fail -- while passing on a clean CI.
Add a package TestMain that points LECTIO_CONFIG at a throwaway temp path,
forcing built-in defaults for every cli test and guaranteeing the suite
never reads or writes the real user config. Suite now green on a Polish
config too.
|
| |
|
|
|
|
|
|
|
|
| |
Reviewed the four EF names missalemeum never returns. George (Martyr),
Stanislaus (Bishop and Martyr), and Zephyrinus (Pope and Martyr) were
correct as best-guessed -- flags cleared as-is. Alexander & Companions
had enumerated only three of the martyrs (omitting Juvenal); since the
English name is the shortened "& Companions", match it with the faithful
Polish "śś. Aleksandra i Towarzyszy, Męczenników". No more # review-pl
flags; all 322 EF names stand.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
EF ferials in the Christmas season rendered with an English season word
in a Polish UI -- "Poniedziałek Christmas" (2026-01-05) -- because the
Polish [seasons] table had no "christmas" key, so season() fell back to
the English title-cased slug.
Add christmas = "Narodzenia Pańskiego" (and the empty season_prep entry),
matching the existing genitive style (Adwentu, Wielkiego Postu). Now
"Poniedziałek Narodzenia Pańskiego". Verified across the whole
Christmas-Epiphany window for both forms; English output unchanged.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
The settings page showed two near-identical version checkbox rows --
"versions" (the terminal compare set) and "web_versions" (the web page's
own default ticks). The first only affects the CLI, so editing it from
the web is pointless and was actively confusing (both rows list the same
wuj/vul/grb/drb boxes).
Remove the "versions" row from the form and stop reading it in
settingsPost, so cfg.Versions is preserved from the live config (same
pattern as offline/width/pager). The web settings now expose only what
the web uses: default_version and web_versions.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Per the target layout: the utility cluster (settings + the pobierz
disclosure) must hold the top-right corner on the same row as the reader
link, not drop onto a second full-width line below the controls.
Make #controls itself non-wrapping so the side cluster keeps the corner;
the left controls (.controls-main) absorb any tightness by wrapping their
OWN items onto a further line (min-width:0 lets them shrink). At the
64rem page width the whole bar cannot fit every left control AND the
corner cluster on one line, so a trailing control (layout) wraps beneath
-- the intended block-on-the-left, cluster-in-the-corner shape. A tighter
column gap buys a little room; on phones (<=40rem) the bar wraps normally.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Finish the top-bar rework. The reader entry point now leads the controls
bar on the far left (it was in the right-hand cluster); settings stays in
the top-right cluster.
The flat "download: txt md pdf · kalendarz" strip becomes a single
"pobierz" summary that opens a small floating panel with two rows:
- a month calendar with its own month + year <select> pickers (localised
month names, both pre-selected from the shown date) and a PDF button
that hits /calendar?month=YYYY-MM;
- the shown day's readings as txt/md/pdf, labelled with the date.
The panel is absolutely positioned under the link so opening it doesn't
reflow the bar. indexData gains MonthOpts/YearOpts (a calOpt list); the
year picker is a small window around the shown year.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The EF (traditional) calendar showed English memorial names even with
the UI switched to Polish, because tridentine-calendar.ini carried only
name.en. Add name.pl to all 322 sanctoral entries.
Source: missalemeum.com's Polish propers (/pl/api/v5/proper/DATE), the
authoritative Polish traditional-calendar naming -- paired to each entry
by the celebration id shared across its /en/ and /pl/ responses, fetched
across two years so saints superseded by a Sunday in one year are still
resolved. 318 entries matched that way; a missalemeum source typo
("Dokotra" -> "Doktora") is corrected in the two it affected.
The remaining 4 -- George, Alexander & Companions, Stanislaus,
Zephyrinus -- are never returned by missalemeum in the fetched years
(superseded every time); they carry a best-guess Polish name tagged with
a "# review-pl" comment for a human to verify.
|
| |
|
|
| |
Lectionary becomes settings-only (kept as a hidden field so readings/export/calendar still use the configured value); mono toggle removed (settings has it). The reader link is uppercased + bold as the primary action.
|
| |
|
|
|
|
|
| |
Wrap the essential controls in a single .controls-main block that wraps
internally, so reader/settings + downloads stay at the TOP-right instead of
dropping to a second row. #controls (index only) becomes top-aligned; the
reader's .controls form is untouched.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Daily page (index.html):
- Date arrows now step the date input client-side and dispatch its change, so
they move relative to the CURRENT day and update the shown date (they were
stuck one step from the initial date, computed server-side).
- Theme picker removed (theme lives only in /settings now); bookmarks link
removed (bookmarks belong to the reader, not the daily readings).
- reader/settings nav + the download links move to a right-aligned .controls-side
cluster; essential controls (date, lectionary, versions, parts, layout, mono)
stay on the left. mono stops its change bubbling so it no longer refetches.
Reader (reader.html + RenderPassage): a bookmarked verse now shows a red "*"
(end of line in columns, after the verse number interlinear). Threaded a
marked set (keyed "chap:verse") through the reader render path only; the daily
RenderReadings path is untouched.
Settings (settings.html): Save button moved to the top; removed offline (dead),
width and pager (CLI/TUI-only, no web effect) -- their config values are
preserved since the handler no longer reads/zeroes them.
Footer: source/licence centred.
Web tests + full suite green both build modes.
|
| |
|
|
|
|
|
| |
A verse that has a bookmark now shows a red "*" at the end of its last line, so
saved verses are visible while reading. The set of bookmarked verses for the
current book+chapter is refreshed on chapter load, on save, and on returning
from the bookmarks list (one store read each). Test covers the flag + render.
|
| |
|
|
|
|
|
|
|
| |
Bookmarks stored tags but the list neither showed them nor let you use them.
Now each row shows "Ref — note #tag1 #tag2", and `/` opens a live tag filter
(case-insensitive substring over a bookmark's tags): type to narrow, Enter keeps
the filter while j/k navigate the filtered list, Esc clears it. Navigation,
open and delete all act on the visible (filtered) list. Reuses the store's
existing tag data; help keybar (en/pl) updated; test covers filter/keys.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
~3,800 verses carried their own verse number at the start of the text (a
biblia.info.pl harvest artifact concentrated in the deuterocanonical books --
Sirach, 1-2 Maccabees, Wisdom, Judith, Baruch, at 90-98% of each, plus 3 strays
in Ezra/Proverbs). E.g. Sirach 4:4 read "4 Nie odrzucaj..." instead of "Nie
odrzucaj...". It passed every check: verse counts are unaffected, and the
verses aren't short.
Strip a leading token only where it exactly equals the verse number (so a
genuine "40 dni" in a non-matching verse is untouched), and only when text
follows. 3797 verses fixed; 35,810-row parity preserved, no verse emptied, no
new warnings; --corpus-check wuj still clean; make test green.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The count-based checks (gap, duplicate, missing chapter) only see a verse's
presence, so a verse that IS there but truncated -- a lost opening line, a merge
artifact, the exact class that lost 44 psalm openings and Acts 6:5 from the old
Wujek scrape -- passes silently.
Add a warning for it, compared CROSS-CORPUS to the aligned Vulgate verse (never
within the chapter). That is deliberate: a genuinely terse verse ("Non occides",
"Jesus wept") is short in the Vulgate too, so it is not flagged; only a corpus
stub against a substantial Vulgate verse fires (corpus <12 chars, <1/4 of a
Vulgate verse >=40). Rune-counted (script-agnostic) and skipped on the Psalms
when the corpus renumbers them (psalm_system != vulgate), where per-verse
alignment with the Vulgate would not hold.
Warning only, never an error. Zero false positives across vul/wuj/drb/grb;
a `stub` testdata fixture (Genesis 1:1 = "x") exercises a real hit.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Since 51c0f4e split the corpora (only vul embedded by default; wuj/drb/grb
behind -tags fullbible), `go test ./...` on the default build was red across six
packages -- every failure was a test assuming an optional corpus is present.
Guard those assertions with a skip keyed on bible.Meta(code), so they run under
-tags fullbible and skip -- not fail -- on the default vul-only build. Mixed
tests are split into subtests so the always-embedded vul assertions and pure
logic (pl->vul fallback, explicit passthrough, bt-rejection, i18n labels) keep
running on both builds. Test-only change; no product code or corpora touched.
- internal/bible: TestVerses, TestLookup, TestCorpusBooks, TestChapters,
TestGrbNoApparatusMarkers, TestCrossChapterRange* (requireCorpus helper).
- internal/cli, config, render, tui, web: the same pattern for their
corpus-dependent tests.
- Fixes an index-out-of-range panic in internal/tui's reader tests that was
aborting the package binary and masking 3 further corpus-absence failures
(TestReaderBookmarkFlow, TestReaderChapterJump, TestReaderRemembersPlace).
Verified: `go test ./...` and `go test -tags fullbible ./...` both green (0 FAIL);
guards active only on the default build (29 skips vs 1 unrelated pre-existing);
gofmt and go vet clean.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
grb failed corpus-check outright: 15 errors, and two whole books absent from
lectio at runtime with no error and no warning.
Upstream grb is a standalone Septuagint reader carrying 87 books. lectio needs
one uniform canon, so scripts/gen-grb-lectio.py derives the 73 books vul has
rather than forking -- upstream stays intact and keeps everything.
Eleven books have no Vulgate counterpart and are dropped, including 2 Esdras,
which upstream's README explains IS Ezra + Nehemiah under the Septuagint's
name; verified byte-identical, so nothing is lost. Five books ARE canonical
under other names and are remapped, and the verse counts show which witness
the Vulgate follows -- Jerome translated Theodotion, not the Old Greek:
Bel and the Dragon (Theodotion) 42 = vul Daniel 14 (42) exact
Bel and the Dragon (LXX) 37 no
Sussana (Theodotion) 64 = vul Daniel 13 (65)
Sussana (LXX) 37 no
Letter of Jeremiah 73 = vul Baruch 6 (72)
Wisdom of Solomon 435 = vul Wisdom (439)
Upstream's plain "Daniel" is the Old Greek and is missing chapter 4 outright,
so Theodotion supplies Daniel throughout: complete, and the tradition the
lectionary actually cites. lectio thereby GAINS Wisdom, Daniel 4, Daniel 13-14
and Baruch 6 in Greek rather than losing them.
Three upstream defects are repaired in transit:
* 408 rows carried 5 fields, not 6 -- a lost tab fused the book number and
chapter ("281" = book 28, chapter 1). Every one was in Hosea or Zechariah,
and neither book had a single well-formed row, so bible.go skipped both
entirely. Hosea (197 verses) and Zechariah (211) are back.
* 5 merged verse labels ("27-28") that strconv.Atoi turns into verse 0.
* A UTF-8 BOM welded to the first book name, making "Genesis" a phantom
74th book matching nothing.
The SBLGNT apparatus sigla are stripped, as TestGrbNoApparatusMarkers
requires; regenerating from raw upstream reintroduces ~8700 of them.
grb now passes. The remaining warnings are the Septuagint being itself --
Jeremiah is LXX-numbered (grb 33:2 is the Vulgate's 26:2), Esther integrates
its additions into chapters 1-10, LXX Malachi has three chapters, and 3
Kingdoms carries supplements like 10:22a that upstream stores as a duplicate
verse 22. Silencing those would mean deleting real Greek text.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Eight corpus-check warnings, of two kinds.
Three chapters (Exodus 40, Genesis 49, Song of Solomon 1) held exactly as many
verses as the Vulgate but numbered with a gap. The count pins the mapping, so
renumbering 1..N is safe and changes no text.
Five chapters were genuinely short. The missing verses came from get.bible's
douayrheims -- the same public-domain source and API scripts/gen-deutero.py
already uses for this corpus, so no new provenance is introduced.
Scope was deliberately narrowed to the flagged chapters. A first pass over
every chapter shorter than the Vulgate pulled in 938 verses, 820 of them in
Psalms -- but drb.ini declares psalm_system = drb, a different numbering, so
matching by Vulgate verse number there would have inserted the wrong text
under the wrong numbers across the Psalter.
One warning remains and is not a defect: Baruch 6 runs 1-72 with verse 37
absent in drb and in get.bible alike, a genuine Douay/Vulgate versification
difference faithfully represented.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Wujek corpus was missing text and mis-numbering what it had: 453
corpus-check warnings, 8 absent chapters, 84 duplicate rows, and 357 chapters
holding fewer verses than the Vulgate.
Most of it was never a sourcing problem. The original harvest of
biblia.info.pl assumed one verse is one <p>, but many psalms print the
superscription in the anchored paragraph and the psalm's opening line in an
unanchored one behind a drop cap -- so 44 psalms lost their first line, and
Acts 6:5 and others went the same way. Re-harvested with the anchor treated as
a verse START rather than a whole verse (scripts/scrape-wujek.py), which also
had to cope with four anchor shapes across books, hidden page markers opening
paragraphs mid-verse, chapter ids that are simply wrong (Mark labels 87
anchors "15:*" across chapters 14-16), and Psalms heading its divisions
"Psalm CXVII" where every other book says "Rozdzial N".
Structure was then repaired against the Clementine Vulgate, by hand where a
rule would have guessed:
* The Acts 5 interleaved three streams -- Acts 4:27-37 duplicated, the real
5:1-37, and 5:38-39 mislabelled 28-29. Verified against the Latin, the
duplicates dropped, the two renumbered. Acts 4:27 kept the site's own
wording in place of a 1962 reading, removing a seam.
* The site heads psalms by Hebrew division; its "Psalm 114" is two psalms.
Split into Vulgate 113:9-26 and 114:1-9, confirmed at all four boundaries.
* A corrupt anchor for 1 Chronicles 9:11 pushed 34 paragraphs of genealogy
into chapter 10. Counts corroborate: 10 + 34 = 44 verses, remainder 14,
both exactly the Vulgate's.
* 16 chapters looked short at the end; only two verses were truly absent.
The rest were merges, split at anchors read off the Latin -- including one
across a chapter boundary (Colossians 4:1 sat inside 3:25) and four
numbering offsets where a mid-chapter merge shifted everything after it.
wuj now carries exactly the Vulgate's verse set: 35810 rows, every one of the
1334 chapters matching, no duplicates, no gaps. corpus-check: 0 warnings.
The ~300 verses that could not come from biblia.info.pl are recorded in
NOTICE; they are not public domain.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add opt-in flags so clectio's tables can be regenerated from a customized
calendar instead of only the embedded universal one:
clectio-gen -caldir DIR -use a,b [-sanctorale DIR] <new|old> y0 y1 out/
- -caldir + -use stack calendar layers (rank, colour, name, reading.*) over the
calendar; -sanctorale DIR applies a full of.ini/ef.ini replacement.
- The BOOK table stays hermetic (LECTIO_CONFIG still points nowhere), so the
generator can't read a stale user books.ini -- calendar customization and the
book aliases are kept separate concerns.
- config.SetCalendarsDir lets CalendarsDir be pointed at an explicit layer dir
without a full config tree (and without an unrelated books.ini there).
Verified end to end: a layer adding a feast with a proper gospel regenerates
into liturgy_of.h + verses_of.keys, and the rebuilt clectio shows it. Default
(no flags) output is byte-identical to before. make test green.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replace the static examples/sanctorale-of.ini with a `--cal-dump NAME` flag
that writes the running universal calendar to ~/.config/lectio/calendars/NAME.ini
as a fully-commented layer template (every celebration present, all commented).
Uncomment one day and edit a field to override it; enable with `use = NAME`.
- Form-aware: respects -l/--lectionary, so `-l trad --cal-dump x` dumps the 1962
calendar (322 entries) and the default dumps the OF calendar (212 entries).
- Entries sorted by date then slug; refuses to overwrite an existing file.
- Always in sync with the embedded (or sanctorale-overridden) calendar, so no
stale checked-in template to maintain.
- Update help text, man page (OPTIONS/FILES/EXAMPLES) and README to match;
drop examples/sanctorale-of.ini.
|
| |
|
|
|
|
|
|
|
| |
On its own, `--year N` now prints a human-readable overview of the year's key
dates -- season boundaries, solemnities and feasts of the Lord -- computed from
the engine for the configured form (and custom-calendar layers), paged when a
pager is configured. With --format json|ical it still emits the machine
calendar (runFeed) as before. Numbered seasonal Sundays and Octave weekdays are
omitted from the solemnity list (the season boundary already marks them).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The help text predated this session's changes. Update all three binaries:
- Taglines: drop "(Polish + 4 versions)" -> "offline ... daily readings (OF + EF)".
- Versions: state that only the Latin Vulgate is built in; wuj/grb/drb are
optional (make build-full, or drop <code>.tsv/.ini into the corpora dir); a
missing version renders "(not in <code>)".
- --ui-lang: now any code (en, pl, ...), not just pl|en; note names/<code>.ini,
ui/<code>.ini, custom calendars and the sanctorale override.
- lectio-ui: drop the removed "bt" version and the no-op -o/--offline flag from
the help (the tool is fully offline; --offline only ever dropped bt).
- lectio-web: drop -o/--offline; add a one-line description of what it serves.
No behaviour change; full suite green.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
hermetic
Two EF Ember-day lessons ("Osee 14:2-10", "2 Esd. 8:1-10") rendered as
"(not in vul)" because the lookup path (ResolveBook, English dialect) lacked
these Douay-Rheims book forms -- they existed only in the Latin dialect, which
ResolveBook does not consult. Add them to the [en] dialect so both lectio and
clectio resolve them (the text is present in vul: Hosea 14, Nehemiah 8).
Also make clectio-gen hermetic: it now points LECTIO_CONFIG at a nonexistent
path so it always uses the EMBEDDED calendar/lectionary/book table, never the
running user's ~/.config/lectio (whose stale books.ini was silently dropping
~30 EF readings from the generated data). It warns on any reading it cannot
resolve. Full range 2025-2054 now generates with 0 dropped readings.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
clectio (~/git/projects/clectio) is a tiny suckless-C daily-readings build
that compiles the calendar, citations and scripture text in. clectio-gen is
its data compiler: it reuses this engine to compute, for a year range, each
day's name/colour/readings and emits corpus-independent C tables plus the
verse KEYS, so the C side is a dumb lookup and the hard liturgical logic
stays here (oracle-validated).
- bible.LookupKeyed(version, ref) returns each resolved verse's
(book, chapter, verse) key, mirroring Lookup's splitting/versification.
clectio-gen uses it to record the exact pericopes a lectionary cites.
- Verified: clectio's output is byte-identical to lectio's readings, day
names 157/157 over a 3-year sample.
|
| |
|
|
|
|
|
|
|
|
| |
The one-shot config.toml -> config.ini and books.toml -> books.ini
migrations (a transition aid from the pre-INI format) are removed, along
with the github.com/pelletier/go-toml/v2 dependency and the now-dead
`toml:` struct tags. The live config format has been INI for many
releases; anyone still on a .toml recreates it (the format is
self-documenting on first run). Leaves 3 direct deps, all in active use
(bubbletea, lipgloss, go-pdf/fpdf). Tests updated to write INI.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The universal calendar of saints can now be refreshed or replaced without a
rebuild: if ~/.config/lectio/sanctorale/of.ini (OF) or ef.ini (EF) is present
and parses, caldata.Base uses it instead of the embedded calendar; a missing or
malformed file falls back to the embedded default, so the binary stays
self-contained and correct out of the box. Local diocesan/national additions
keep layering on top via calendars/ + `use` (unchanged). The temporal cycle and
precedence rules stay in code -- only the sanctorale is data.
- caldata.SetSanctoraleDir hook (mirrors bible/naming/i18n); Base() prefers the
external file per form. config.SanctoraleDir(); wired in the CLI, TUI and web
entry points. Tests cover override, no-file, and malformed-file fallback.
- README: new "Calendar of saints" section (two tiers: overlay via `use`,
replace via sanctorale/<form>.ini); config comment notes the override.
|
| |
|
|
|
|
|
|
|
|
|
| |
Add name.pl to the 132 universal-calendar celebrations that lacked it, so all
212 now carry Polish names (was 80). They follow the existing liturgical style
-- genitive case, "św. <name>, <title>" / "świętych ...", feast events in the
genitive -- hand-curated from standard Polish nomenclature and keyed to each
entry's name.en/name.la. Polish patrons use their Polish forms (Adalbert ->
św. Wojciech, John of Kanty -> św. Jana Kantego, Hedwig -> św. Jadwigi
Śląskiej). Verified: feast/solemnity saints render their Polish name as the
day header, optional memorials appear as Polish options in the day's others.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The interface chrome (version labels, TUI keybar/messages, CLI banner words,
web control labels, section-heading words) was English/Polish hardcoded in Go.
It is now data: the English and Polish tables ship as embedded lang/en.ini and
lang/pl.ini, and any language is user-overridable at <config>/ui/<code>.ini,
resolved per key with an English fallback. With ui_language = <code> plus a
names/<code>.ini, the WHOLE interface -- chrome, day names, saint names -- is
translatable without a rebuild.
- i18n.Get loads the embedded English baseline, overlays the embedded/user
language file, caches per lang; field <-> INI-key mapping is by reflection
(lang.go) so the tables and files stay in sync automatically. Edge-space
values (e.g. "error: ") are double-quoted so the INI trim keeps them. The
Go tables move to golden_test.go; TestGoldenMatchesEmbedded asserts the
embedded files still parse back to them, and TestGenerateLangFiles
regenerates them (LECTIO_GEN=1).
- config.UIDir(); wire i18n.SetUserDir in the CLI, TUI and web entry points.
- README/config: document ui/<code>.ini alongside names/<code>.ini.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Add internal/naming, which renders temporal day names and celebration
display names from the calendar engine's slugs in any language. English is
the built-in baseline; a language is data -- an embedded lang/<code>.ini
(pl shipped) and/or a user file at <config dir>/names/<code>.ini that
overrides it key by key. Names compose from a small vocabulary plus
per-language format templates, so word order and grammatical case can
differ (e.g. Polish genitive "3. Niedziela Okresu Zwykłego"); any string a
language omits falls back to English.
- Move day-name generation out of calendar (calendar.HumanizeSlug removed,
calendar stays a pure engine) into naming.DayName; the English golden
cases carry over verbatim.
- naming.CelebrationName unifies the three duplicated resolvers
(cli/readings/calfeed): name.<lang> -> English -> Latin -> humanized slug.
Saint names stay in the calendar data (name.<lang>), overridable via
calendar layers.
- config: ui_language now accepts any code (lower-cased, not clamped to
en/pl) so names/<code>.ini applies; UI chrome still resolves en/pl and
falls back to English. Add NamesDir(); wire naming.SetUserDir (and the
previously unwired bible.SetUserCorporaDir) in the TUI and web mains too,
so external corpora and name files work across all three binaries.
|