<feed xmlns='http://www.w3.org/2005/Atom'>
<title>lectio.git/internal/readings, branch main</title>
<subtitle>offline Catholic daily readings and liturgical calendar in Go, with CLI, TUI and web clients</subtitle>
<id>https://git.labunix.xyz/lectio.git/atom?h=main</id>
<link rel='self' href='https://git.labunix.xyz/lectio.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/'/>
<updated>2026-08-24T14:35:01Z</updated>
<entry>
<title>perf(readings): stack calendar layers and load the book table once per Days call</title>
<updated>2026-08-24T14:35:01Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-24T14:35:01Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=b6ee8f09ad2c0bc9e83394e2427de861eb1e2a72'/>
<id>urn:sha1:b6ee8f09ad2c0bc9e83394e2427de861eb1e2a72</id>
<content type='text'>
mobile.Days (dlectio's 7-day calendar view) called readings.Load once per
date. Load's offlineLoad re-ran caldata.Stack (parses the embedded
calendar INI, plus any user calendar layer) and bible.LoadBookTable
(parses the embedded books.ini, plus any user override) on every call,
even though neither depends on the date -- only on cfg.Selection().Form
and cfg.Use, which mobile.Days holds fixed across its whole loop.

Verified before changing anything: isolated benchmarks put Stack+
LoadBookTable at ~1.1ms/call (OF) and ~1.6ms/call (EF) -- real INI
parsing and, for a user override, file I/O -- and for the OF form that
redundant work was ~67% of a 7-day view's total time.

Load gains a Prepared value (the layer stack + book table) and a
Prepare/LoadWith pair: Prepare builds a Prepared once, LoadWith reuses
it across dates. Load itself is unchanged, still calling Prepare on
every invocation -- every existing caller keeps its current behaviour
untouched. mobile.Days now Prepares once and loops LoadWith; mobile.Day
picks up the same fix for its own two same-cfg Load calls.

Benchmarked (interleaved before/after pairs, to control for machine
thermal drift): the OF 7-day view (BenchmarkDaysWeek) drops from
~11.5ms to ~6.4ms/op (allocs 53359 -&gt; 16347, -69%), an EF 7-day view
(BenchmarkDays7EF) from ~74ms to ~66-73ms/op (allocs 299204 -&gt; 253815,
-15%; the EF form's per-day calendar computation dominates its total
cost far more than OF's does, so the fix's share of the win is smaller
there), and a single Day call (BenchmarkDay1) from ~4.3ms to ~2.9ms/op
(allocs 15357 -&gt; 9192, -40%).

Output identity verified separately (not part of this diff): a 288-case
sweep of mobile.Day/mobile.Days across both forms, both UI languages,
all four corpora, a leap day, the Sacred Triduum, a Requiem day, and
windows spanning Christmas/Pentecost/Assumption/All Souls produced
byte-identical (SHA-256-equal) JSON before and after this change.

New TestLoadWithAgreesWithLoad asserts LoadWith(Prepare(cfg), cfg, opts)
equals Load(cfg, opts) for every case, so the fast path cannot silently
drift from the slow one. go test ./... and make ci (both build tags,
oracle/differential suite included) are green.
</content>
</entry>
<entry>
<title>calendar/readings: report Sunday as its own display rank, not solemnity</title>
<updated>2026-08-05T20:24:53Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-05T20:24:53Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=4855ef2a667b7ea71092e0582db5aff1838a0d63'/>
<id>urn:sha1:4855ef2a667b7ea71092e0582db5aff1838a0d63</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>readings: PartIDs(new) stops declaring aklamacja, which the engine never emits</title>
<updated>2026-08-05T12:10:34Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-05T12:10:34Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=eb4a02205f5b3b972c44b854d5becbbd0b522981'/>
<id>urn:sha1:eb4a02205f5b3b972c44b854d5becbbd0b522981</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>i18n: pin the Polish part labels; cross-reference the part-ID orders</title>
<updated>2026-08-03T22:05:55Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-03T22:05:55Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=70c504148ca9ddf7fdb31162f5f8da7e118fca45'/>
<id>urn:sha1:70c504148ca9ddf7fdb31162f5f8da7e118fca45</id>
<content type='text'>
</content>
</entry>
<entry>
<title>readings: 1962 part labels become i18n data; export PartIDs</title>
<updated>2026-08-03T21:51:54Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-03T21:51:54Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=e3d551ebb8f6ac2bf1a7027991a4222e83309a39'/>
<id>urn:sha1:e3d551ebb8f6ac2bf1a7027991a4222e83309a39</id>
<content type='text'>
</content>
</entry>
<entry>
<title>i18n: correct rank doc comments and pin the Polish wording</title>
<updated>2026-08-03T21:50:26Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-03T21:50:26Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=f94ceaae997bce2168a5ab9e64a0c3afeafe0cf6'/>
<id>urn:sha1:f94ceaae997bce2168a5ab9e64a0c3afeafe0cf6</id>
<content type='text'>
</content>
</entry>
<entry>
<title>liturgy: carry the observed rank on DayInfo</title>
<updated>2026-08-03T21:40:30Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-03T21:40:30Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=3d3ad4ba90c4d7dea4730ef129f8c9e065f05d6e'/>
<id>urn:sha1:3d3ad4ba90c4d7dea4730ef129f8c9e065f05d6e</id>
<content type='text'>
</content>
</entry>
<entry>
<title>naming: localise liturgical day names in any language</title>
<updated>2026-07-28T16:15:29Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-07-28T16:15:29Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=539a7c71b60115144959f712ef5966f48c63f9f0'/>
<id>urn:sha1:539a7c71b60115144959f712ef5966f48c63f9f0</id>
<content type='text'>
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/&lt;code&gt;.ini
(pl shipped) and/or a user file at &lt;config dir&gt;/names/&lt;code&gt;.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.&lt;lang&gt; -&gt; English -&gt; Latin -&gt; humanized slug.
  Saint names stay in the calendar data (name.&lt;lang&gt;), overridable via
  calendar layers.
- config: ui_language now accepts any code (lower-cased, not clamped to
  en/pl) so names/&lt;code&gt;.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.
</content>
</entry>
<entry>
<title>refactor: remove the niedziela/missalemeum scrapers, bt, traditional_lang</title>
<updated>2026-07-28T10:50:31Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-07-28T10:50:31Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=7b220084cf3951c8cde0582efdfcf628afc64336'/>
<id>urn:sha1:7b220084cf3951c8cde0582efdfcf628afc64336</id>
<content type='text'>
The daily view now computes entirely offline (previous commit), so retire the
network path and everything that served it:

- Delete internal/tradlit (missalemeum) and the niedziela scraper from
  internal/liturgy (fetch/store/parse + fixtures); keep Section, DayInfo and
  ExtractCitation.
- Remove the "bt" version everywhere (render gatherBT + branches, config,
  i18n, web form, TUI) and bible.ToEnglishRef (Polish citation converter).
  A legacy config carrying "bt" migrates to "wuj" on load (config.migrateBT).
- Remove the traditional_lang config field and the -g/--lang flag from all
  three binaries.
- Drop the now-dead flags -R/--refresh, -o/--offline, -u/--update,
  -C/--clean and the harvest/clean commands.
- New defaults: versions = wuj,vul,grb,drb; default_version = vul.

Update the README (offline-by-design, no harvest/update), help text, and
stale niedziela/bt doc comments. Tests updated for the offline reality;
go test ./... and go vet ./... are clean, all three binaries build and run
offline (OF + EF, compare, web).
</content>
</entry>
<entry>
<title>feat(readings): compute the daily view offline (OF + EF)</title>
<updated>2026-07-28T09:57:45Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-07-28T09:57:45Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/lectio.git/commit/?id=feede51697be870ae183a95b513ef64f031dbd0f'/>
<id>urn:sha1:feede51697be870ae183a95b513ef64f031dbd0f</id>
<content type='text'>
Route readings.Load through the embedded calendar engine and lectionary
data instead of the niedziela/missalemeum scrapers. The daily view now
computes each day (calendar.Compute + caldata.Readings) and renders text
from the public-domain corpora, with citations resolved per corpus.

- bible.OFRef: normalise an English-canonical OF citation (drop sub-verse
  letters, ";" -&gt; ",") and renumber Psalms for the target Psalter
  (Hebrew-&gt;Vulgate chapter for vul/grb/wuj; DRB title-fold verses for drb).
- liturgy.Section gains Ref (English-canonical lookup ref) alongside
  Citation (sigla-dialect display); the loader fills both, resolveRef uses
  Ref, headings/citation command show Citation.
- EffectiveVersions always drops "bt" (no offline corpus); the single
  daily version defaults to vernacularVersion (reading corpus else Latin).

Scraper packages remain in the tree, unreferenced, pending removal.
</content>
</entry>
</feed>
