aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-27 13:52:57 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-27 13:52:57 +0200
commit72f9213bd8532b0527a1585cb3a87e3c9e061e1a (patch)
tree52f775cdfecb74bc3ca37c491f76408089448543 /docs
parentd23ab8402f8f0beb07b3df9f3cfeaa70448cb9fc (diff)
downloadlectio-72f9213bd8532b0527a1585cb3a87e3c9e061e1a.tar.gz
lectio-72f9213bd8532b0527a1585cb3a87e3c9e061e1a.zip
docs: implementation plan for the EF (1962) calendar engine
Diffstat (limited to 'docs')
-rw-r--r--docs/superpowers/plans/2026-07-27-lectio-ef-calendar-engine.md47
1 files changed, 47 insertions, 0 deletions
diff --git a/docs/superpowers/plans/2026-07-27-lectio-ef-calendar-engine.md b/docs/superpowers/plans/2026-07-27-lectio-ef-calendar-engine.md
new file mode 100644
index 0000000..c74e737
--- /dev/null
+++ b/docs/superpowers/plans/2026-07-27-lectio-ef-calendar-engine.md
@@ -0,0 +1,47 @@
+# EF (1962) Calendar Engine Implementation Plan
+
+> REQUIRED SUB-SKILL: superpowers:executing-plans. Spec: docs/superpowers/specs/2026-07-27-lectio-ef-calendar-engine-design.md.
+
+**Goal:** Compute the 1962 (EF) liturgical day offline, form-aware in the existing engine (`sel.Form == "old"`), validated against the missalemeum per-date API.
+
+**Global constraints:** `calendar` stays stdlib-pure; `Compute` total. Both OF and EF oracles must pass (OF: 0 season mismatches; EF: 0 season mismatches). Reuse Computus/merge/INI/result + custom layers.
+
+---
+
+### Task 1: Rank int enum → unified string token (OF refactor, oracle-gated)
+**Files:** `internal/calendar/types.go`, `precedence.go`, `calendar.go`, `temporal.go`, `internal/cli/liturgy.go`, tests.
+- [ ] `type Rank string`; consts `RankFerial="ferial"`, `RankOptional="optional"`, `RankMemorial="memorial"`, `RankFeast="feast"`, `RankSolemnity="solemnity"`. `ParseRank` validates → `Rank(s)` or `RankFerial`.
+- [ ] Add `func ofRankOrder(r Rank) int` (ferial0<optional1<memorial2<feast3<solemnity4). Replace the two `cel.Rank < RankSolemnity` / `< RankFeast` sites in `calendar.go` with `ofRankOrder(...)` comparisons. Equality checks (`== RankSolemnity`) stay as-is (strings).
+- [ ] `rankLabel` (cli) switches on the string values.
+- [ ] Build; `go test ./internal/calendar/ ./internal/cli/`; **re-run OF oracle → 0 season mismatches**. Commit.
+
+### Task 2: EF seasons + `temporalEF`
+**Files:** `internal/calendar/types.go` (season consts), `internal/calendar/temporal_ef.go` (new); Test `temporal_ef_test.go`.
+- [ ] Add Season consts: `Septuagesima`, `Passiontide`, `TimeAfterEpiphany`, `TimeAfterPentecost` (advent/christmas/lent/easter/triduum shared).
+- [ ] `func temporalEF(date time.Time) temporalDay`: Computus + `adventStart` → the 1962 seasons (Advent; Christmastide + octaves; Time after Epiphany; Septuagesima/Sexagesima/Quinquagesima; Lent; Passiontide; Holy Week/Triduum; Paschaltide + octaves; Time after Pentecost incl. Trinity/Corpus/Sacred Heart, resumed Epiphany Sundays, Christ the King = last Sun of October, Last Sunday). EF ranks on temporal cels (`class-1` Sundays of Advent/Lent, etc.).
+- [ ] Unit tests for a handful of dates (Septuagesima Sunday `easter-63`; a Sunday after Pentecost; Christ the King = last Sun of Oct). Season boundaries validated wholesale by Task 6's oracle. Commit.
+
+### Task 3: `precedenceEF` (1960 rubrics)
+**Files:** `internal/calendar/precedence_ef.go` (new); Test `precedence_ef_test.go`.
+- [ ] `efRankOrder(Rank) int` (class-1 highest … ferial/commemoration lowest). `precedenceEF(candidate) int` + `pickEF` mirroring the OF pattern but by 1960 class/occurrence. Impeded I-class transfer handled in the EF Compute branch.
+- [ ] Unit tests: a I-class feast beats a III-class feast beats a IV-class feria; commemoration lowest. Commit.
+
+### Task 4: `Compute` form branch
+**Files:** `internal/calendar/calendar.go`; Test `calendar_test.go`.
+- [ ] `Compute` branches on `sel.Form`: `"old"` → `temporalEF` + EF candidate build + `precedenceEF`/`pickEF` + EF transfer; else existing OF path. Shared: merge, buildCelebration, result assembly, cycles (cycles are OF-only concepts → leave SundayCycle/WeekdayCycle empty for EF).
+- [ ] Test: an EF layer's `class-1` feast observed on its date; OF path unchanged. Commit.
+
+### Task 5: `caldata.Tridentine()` + form-aware `Stack`
+**Files:** `internal/caldata/tridentine-calendar.ini` (new, initial subset), `internal/caldata/caldata.go`; Modify `internal/cli/liturgy.go`; Tests.
+- [ ] Embed `tridentine-calendar.ini` (a real initial 1962 sanctoral subset: the great feasts with `class-1…4`, EF dates/colours/names). `Tridentine() calendar.Layer`; `Base(form) calendar.Layer` (old→Tridentine, else Universal); `Stack(form, dir, use)` prepends `Base(form)`.
+- [ ] Update `runLiturgy` to `caldata.Stack(cfg.Selection().Form, dir, cfg.Use)`; **remove the EF guard**; form-aware `rankLabel`.
+- [ ] Tests: `Tridentine()` loads; `Stack("old",…)` base is the EF layer. Commit.
+
+### Task 6: missalemeum EF oracle
+**Files:** `scripts/build-oracle-ef.sh` (new), `internal/calendar/testdata/oracle-ef.json` (generated), `internal/calendar/oracle_ef_test.go` (new). Iterate `temporal_ef.go` + data.
+- [ ] `build-oracle-ef.sh`: fetch `https://www.missalemeum.com/en/api/v5/proper/{date}` per day over 2024–2028; map `tempora`→season/week, `rank`(1–4)→`class-N`, `colors`→colour; write `{date:{season,rank,colour}}`. Not run by `go test`.
+- [ ] `oracle_ef_test.go`: compute each day (Form=old, `[Tridentine()]`), assert **season strictly** (SKIP if snapshot absent); rank/colour informational.
+- [ ] Iterate until 0 season mismatches (document exceptions). Commit snapshot + fixes.
+
+### Task 7: full verification + version bump
+- [ ] `config.Version` → `0.28.0`. `go build/vet/test ./...`; both oracles pass; calendar still stdlib-pure. Live check: `lectio 2025-08-15 --lectionary trad -L` computes the EF Assumption. Commit.