diff options
Diffstat (limited to 'docs/superpowers/specs')
| -rw-r--r-- | docs/superpowers/specs/2026-07-23-lectio-go-rewrite-design.md | 91 |
1 files changed, 82 insertions, 9 deletions
diff --git a/docs/superpowers/specs/2026-07-23-lectio-go-rewrite-design.md b/docs/superpowers/specs/2026-07-23-lectio-go-rewrite-design.md index 9cc8cb3..f0889e3 100644 --- a/docs/superpowers/specs/2026-07-23-lectio-go-rewrite-design.md +++ b/docs/superpowers/specs/2026-07-23-lectio-go-rewrite-design.md @@ -20,12 +20,17 @@ keeps working. `lectio` is a fresh project. ## Non-goals -- Offline lectionary computation (computing the day's citations without the - site) remains the separate `offline_readings` effort. `lectio` fetches the - site like `ewangelia.py`; when an offline engine exists it slots in behind - `internal/liturgy` without changing consumers. +- **Computing** the day's citations from a liturgical-calendar engine (for dates + the site never published, or with no network and no prior harvest) remains the + separate `offline_readings` effort. `lectio` gets citations from the site, or + from a prior `lectio update` harvest — it does not compute them. When an + offline engine exists it slots in behind `internal/liturgy` unchanged. - No new translations beyond the five already supported. +Note: harvesting the site's **published** future sigla (`lectio update`) and +reading them offline *is* in scope — it is the "harvest" path, distinct from +calendar computation. + ## Key decisions | Decision | Choice | @@ -46,7 +51,7 @@ Module: `github.com/lukaszkasprzak/lectio`. Location: `~/git/projects/lectio`. ``` cmd/lectio/main.go -> cli.Run(args, stdin, stdout, stderr) int cmd/lectio-ui/main.go -> load config+data, tui.New(...), tea.NewProgram(...).Run() -internal/liturgy/ fetch + parse niedziela.pl into []Section +internal/liturgy/ fetch + parse niedziela.pl; cache; sigla harvest/offline internal/bible/ embedded corpora + reference lookup + book aliases internal/psalter/ psalm versification (port of psalm_versify.py) internal/render/ text rendering: compare columns, section text (CLI) @@ -93,14 +98,53 @@ subset the tool actually feeds it: - `Fetch(date, refresh) (html, error)` — GET `https://niezbednik.niedziela.pl/liturgia/{date}/Ewangelia` with a browser - User-Agent; cache to `~/.cache/lectio/{date}.html` (honor `XDG_CACHE_HOME`). - Cache only fully-published pages. + User-Agent. Cache only fully-published pages. - `Parse(html) ([]Section, error)` — pick the **new** lectionary tab (`tabnowy0all`), fall back to `tabstary0all` with a warning; extract each section's heading, subtitle, citation, and paragraphs. Fail loudly if the tab is present but empty or absent (layout change). - `Section{Heading, Subtitle, Citation, Paragraphs}`. +### Caching (fast repeat loads) +Two layers under `~/.cache/lectio/` (honor `XDG_CACHE_HOME`): + +- Raw HTML `{date}.html` — skips the network re-fetch of a published page. +- Parsed sections `{date}.json` — skips re-parsing; a repeat load the same day + hits this and is near-instant (no network, no parse). + +Only fully-published pages are cached (an unpublished future date keeps being +retried, never cached as "empty"). `--refresh` bypasses both layers. +`Load(date)` tries JSON → HTML(+parse, write JSON) → fetch(+cache both). + +### Sigla harvest (`lectio update`) and offline use +The site publishes each day's reading **sigla** (the scripture citations) weeks +to months ahead. `lectio update` walks forward from today, fetching each date +and extracting its citations, until it reaches the unpublished horizon (a page +with no readings). It writes them to a persistent TSV: + + ~/.local/share/lectio/sigla.tsv (honor XDG_DATA_HOME) + +One row per reading section: `date <TAB> section_label <TAB> citation`, e.g. + + 2026-07-22 1. czytanie Pnp 8, 6-7 + 2026-07-22 Psalm Ps 63 (62), 2. 3-4. 5-6. 8-9 (R.: por. 2ab) + 2026-07-22 Ewangelia J 20, 1. 11-18 + +`update` merges with the existing file (re-harvesting a date replaces its rows), +warms the HTML/JSON cache for those dates, and reports how many days it added and +the furthest date reached. + +**Offline use.** When offline (config `offline = true`, the `--offline` flag, or +an automatic fallback after a failed fetch), `Load` reads the sigla TSV instead +of the network. If the date is present it builds the sections from the stored +citations and renders the four **embedded** Bible versions from the corpora — so +after one `lectio update`, any harvested day reads fully offline in Wujek Polish, +Latin, Greek and Douay-Rheims. The `pl` version (modern niedziela.pl / Biblia +Tysiąclecia) is online-only and not embedded (copyright); **offline, `wuj` +(Wujek) takes the Polish role** — `pl` is dropped from any version list and +replaced by `wuj` where needed (see Config → `offline`). A date absent from the +harvest gives a clear "run `lectio update` online" error. + ## Versions and psalm systems Ported from `ewangelia.py` constants: @@ -147,6 +191,7 @@ lectio date D [--all] [--raw] [--width N] [--refresh] # D = YYYY-MM-DD lectio compare LIST [--date D] [--all] [--width N] [--refresh] LIST = comma versions (default: config `versions`) lectio show VERSION [--date D] [--all] [--refresh] # one version's text +lectio update [--days N] [--from D] # harvest future sigla to the TSV lectio --version | lectio -v lectio help | lectio -h | lectio <cmd> -h ``` @@ -154,7 +199,11 @@ lectio help | lectio -h | lectio <cmd> -h - `--all` shows every reading (1st/2nd, psalm, acclamation, gospel); default is the gospel only, unless config `all = true`. - `--raw` drops banner/headings for piping. -- `--refresh` bypasses the cache. +- `--refresh` bypasses the cache and re-fetches. +- `--offline` (global) skips the network and uses the sigla TSV; also applied + automatically when a fetch fails. +- `update` harvests forward from today (or `--from D`) up to `--days N` (default: + until the unpublished horizon), writing the sigla TSV. - Flags override config. Exit codes: 0 ok, 1 runtime error (fetch/parse), 2 usage error. @@ -167,6 +216,8 @@ Bubble Tea Elm architecture, per the approved mockup (reader + version-switch): - Keys: `tab`/`shift+tab` cycle versions (order = config `versions`, starting at `default_version`); `←/→` change date (async re-fetch with a loading state); `j/k` and `space`/`b` scroll; `g/G` top/bottom; `r` refresh; `q`/`ctrl+c` quit. +- Offline (config/flag): the version cycle omits `pl` (uses `wuj` for Polish); + dates come from the harvest; a header hint shows the offline state. - Async fetch via `tea.Cmd` returning a `readingsMsg` or `errMsg`; a spinner or "ładowanie…" line while in flight. - Lipgloss styling, theme-neutral (works on light/dark terminals); width-aware @@ -206,11 +257,26 @@ versions = ["pl", "wuj", "vul", "grb", "drb"] # compare set + TUI cycle default_version = "pl" # TUI start / `lectio show` default width = 0 # CLI wrap width; 0 = detect terminal all = false # default to all readings (true) or just the gospel (false) +offline = false # true = never fetch; read only harvested sigla + cache ``` Unknown versions in config are rejected with a clear error. Invalid TOML falls back to defaults with a stderr warning. +`offline = true` (or the `--offline` flag) makes lectio work purely from the +`lectio update` harvest and cache — it never touches the network, and `pl` +(online-only) is dropped in favour of `wuj` as the Polish version: + +- Any version list drops `pl`; if the list had `pl` but not `wuj`, `wuj` takes + its place. So default `versions` become `["wuj","vul","grb","drb"]` offline. +- `default_version`/`show pl` fall back to `wuj` offline. +- A date not present in the sigla harvest gives a clear "not harvested; run + `lectio update` online" error. + +Seeded default is `offline = false` (a fresh install has no harvest yet); a user +who runs `lectio update` on a schedule can flip it to `true` for a fast, +network-free daily read. + ## Porting map (Python → Go) | Python (`ewangelia.py` / `psalm_versify.py`) | Go | @@ -225,8 +291,12 @@ back to defaults with a stderr warning. ## Error handling -- Network failure / unpublished date: clear stderr message, exit 1 (CLI) or an +- Network failure: fall back to the sigla TSV (offline mode) if the date is + harvested — render the four embedded versions, note that `pl` is unavailable. + If the date is not harvested either, clear stderr message, exit 1 (CLI) or an error line in the TUI (stay usable, let the user change date). +- Unpublished future date: "no reading published for this date yet", exit 1; + `update` treats it as the horizon and stops. - Layout change (tab missing/empty): explicit "site layout may have changed" error, exit 1. - A corpus lacking a passage (e.g. deuterocanonical book absent from a version): @@ -241,6 +311,9 @@ back to defaults with a stderr warning. - **psalter**: unit tests for `drb_verse` on titled/untitled/2-line-title psalms. - **liturgy.Parse**: fixture tests against a few cached HTML pages (a normal day, a split-reading feast, an unpublished date), asserting sections/citations. +- **liturgy cache + sigla**: round-trip the parsed JSON cache; harvest sigla from + fixture pages into a temp TSV and read them back; offline `Load` builds sections + from the TSV and renders the embedded versions with `pl` noted unavailable. - **render**: golden-text tests for a compare block and a section, including the refrain dedup and psalm-number divergence. - **config**: load/seed/override tests with a temp `XDG_CONFIG_HOME`. |
