aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-15 00:36:43 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-15 00:36:43 +0200
commitf8d694d0cc19b71598e1ab64254efb069969f0a0 (patch)
tree48e9c2fa7246d43f0d49b4a29fedadc30a2a1c1b /lib
parent124d7e2261c721c4a49f7203efc276088c7cb217 (diff)
downloadcolitur-f8d694d0cc19b71598e1ab64254efb069969f0a0.tar.gz
colitur-f8d694d0cc19b71598e1ab64254efb069969f0a0.zip
kernel+ef: fix round 1 -- lectionary caller-supplied, not eager
Critical (coordinator review): a clean `dune build` produced a `colitur` that died at startup on EVERY subcommand, including ones touching no lectionary data at all. Root cause was two-fold: data/ef/lectionary.sexp was never added to the root default-build alias (only materialised as a side effect of the test suite's own deps, which is why every check in the prior report passed), and Rite_ef.context loaded it as a module-init side effect via failwith, undoing Lectionary.load's own "never raises" promise at a point no caller could catch. Fixed structurally: Rite_ef.context is now a function taking ~lectionary, Lectionary_ef.readings takes ~lectionary, and neither touches the filesystem any more -- the same caller-supplied discipline the sanctoral layer already had, restoring rite_ef.mli's own pre-existing claim about it and leaving a seam for a future diocesan lectionary overlay. bin/main.ml grows load_ef_lectionary, a sibling of load_ef_layer, routed through the same colitur: %s / exit 2 path. data/ef/lectionary.sexp added to the root default alias. Every caller of Rite_ef.context updated to supply it. Also: two new tests that genuinely distinguish chain step 1 from step 2 (19 March 2026, Joseph's own proper over a competing temporal entry; 13 January 2030, Holy Family reached only through the temporal slug, the Baptism entirely absent) -- the prior two tests both survived swapping the chain order. Both new pins verified directly against the real data. The chain's own comment now states plainly that its warrant is lectio's observed behaviour, not a confirmed Missal citation, per the rules register's own open item.
Diffstat (limited to 'lib')
-rw-r--r--lib/rites/rite_ef/lectionary_ef.ml44
-rw-r--r--lib/rites/rite_ef/lectionary_ef.mli18
-rw-r--r--lib/rites/rite_ef/rite_ef.ml13
-rw-r--r--lib/rites/rite_ef/rite_ef.mli20
4 files changed, 59 insertions, 36 deletions
diff --git a/lib/rites/rite_ef/lectionary_ef.ml b/lib/rites/rite_ef/lectionary_ef.ml
index f9ce9ab..ec1aa0a 100644
--- a/lib/rites/rite_ef/lectionary_ef.ml
+++ b/lib/rites/rite_ef/lectionary_ef.ml
@@ -1,37 +1,23 @@
open Colitur_kernel
-(* [data/ef/lectionary.sexp] is located relative to the BUILD TREE, not the
- process's own cwd -- the same reasoning bin/main.ml's own [data_dir]
- documents at length: cwd varies with how the binary that eventually links
- this library is invoked (a user's shell for `dune exec colitur --`, a
- dune cram test's own sandboxed temp directory, `_build/default/test/` for
- `dune test`), and nothing in this project's build pins it to the
- repository root. [Sys.executable_name] resolves through /proc/self/exe on
- Linux, so it reports the executable's own canonical absolute path even
- when launched through a symlink (dune's cram sandbox places exactly one;
- confirmed working there already by bin/main.ml). Every executable that
- links this library -- bin/main.exe, test/test_colitur.exe,
- tools/*.exe -- sits exactly one directory below _build/default/, so
- climbing up twice and back down into data/ef always finds the file,
- regardless of the caller's own cwd. *)
-let data_path () =
- Filename.dirname (Filename.dirname Sys.executable_name) ^ "/data/ef/lectionary.sexp"
-
-(* Loaded once, at module initialisation: the data is year-independent and
- build_day is called 3 074 246 times over the full domain. *)
-let lectionary =
- match Lectionary.load (data_path ()) with
- | Ok l -> l
- | Error e -> failwith ("lectionary_ef: " ^ e)
-
(* Step 1: the observed celebration's own proper.
Step 2: the day's own temporal slug.
- Nothing here encodes "Lent has daily propers": the presence of an entry is
- the discriminator. Verified against lectio -- Lent 1 Monday returns its own
- Ezech 34:11-16, while Advent, Christmas and post-Pentecost Mondays return
- their Sunday's Mass. *)
-let readings ~observed ~temporal ~date:_ ~temporal_at:_ =
+ Nothing here encodes "Lent has daily propers": the presence of an entry in
+ [lectionary] is the sole discriminator -- this function does not branch on
+ season, rank, or any other field to decide whether a temporal slug "ought"
+ to have its own Mass.
+
+ The WARRANT for that shape is lectio's own observed behaviour only, not a
+ confirmed Missal citation: Lent 1 Monday returns its own Ezech 34:11-16,
+ while Advent, Christmas and post-Pentecost Mondays return their Sunday's
+ Mass, in both streams. docs/research/rules-register.md records this
+ openly as unconfirmed against the primary source ("EF reading-selection
+ rules ... Have lectio's behaviour; confirm against the Missal's
+ ferial-Mass rubrics when coding") -- that confirmation has not been done;
+ do not read this comment as citing RG/the Missal for the SELECTION rule
+ itself, only [Lectionary.find]'s presence-or-absence as the mechanism. *)
+let readings ~lectionary ~observed ~temporal ~date:_ ~temporal_at:_ =
match observed.Celebration.citations with
| _ :: _ as cs -> cs
| [] -> (
diff --git a/lib/rites/rite_ef/lectionary_ef.mli b/lib/rites/rite_ef/lectionary_ef.mli
index fe9359e..65fbfe5 100644
--- a/lib/rites/rite_ef/lectionary_ef.mli
+++ b/lib/rites/rite_ef/lectionary_ef.mli
@@ -3,11 +3,29 @@ open Colitur_kernel
(** The EF lectionary resolution chain. All rubric knowledge about what a day
with no proper falls back to lives here, not in the kernel.
+ [lectionary] is caller-supplied, not loaded by this module -- the same
+ reasoning rite_ef.mli's own [context] doc comment already gives for why
+ the sanctoral {!Colitur_kernel.Layer.t} stays a separate argument rather
+ than an embedded field: it lets a caller load data/ef/lectionary.sexp
+ however suits it, and leaves room for a future diocesan/proper
+ lectionary overlay to attach without this module changing at all.
+
+ An eager filesystem read at module initialisation was tried first and
+ reverted (fix round 1, coordinator review): [readings] used to close
+ over a [lectionary] value loaded as a side effect of this module being
+ LINKED, so `colitur easter <year>` -- which touches no lectionary data
+ at all -- died at startup the moment data/ef/lectionary.sexp was
+ missing from a bare `dune build`'s own default target (it was only
+ present because test/dune's own deps happened to materialise it,
+ masking the gap in every test run). See the task report for the
+ reproduction.
+
Steps 1 and 2 only (Task 4): the observed celebration's own proper, else
the day's own temporal slug in the lectionary. A day matching neither
gets [] for now -- the ferial fallback to the preceding Sunday (Task 5)
and the Commons (Task 6) are not built here. *)
val readings :
+ lectionary:Lectionary.t ->
observed:Vocab_ef.rank Celebration.t ->
temporal:(Vocab_ef.season, Vocab_ef.rank) Temporal.t ->
date:Date.t ->
diff --git a/lib/rites/rite_ef/rite_ef.ml b/lib/rites/rite_ef/rite_ef.ml
index 4cf52a6..ded960b 100644
--- a/lib/rites/rite_ef/rite_ef.ml
+++ b/lib/rites/rite_ef/rite_ef.ml
@@ -11,7 +11,16 @@ module Lectionary_ef = Lectionary_ef
open Colitur_kernel
-let context : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
+(* [~lectionary], not a value closed over an internal load: fix round 1
+ (coordinator review) found the previous version -- [context] as a plain
+ value, [Lectionary_ef] loading data/ef/lectionary.sexp as a side effect
+ of being linked -- made `colitur easter <year>` (no lectionary data
+ touched at all) die at startup the moment that file was absent from a
+ bare `dune build`'s own default target. A function mirrors how the
+ sanctoral [Layer.t] already travels: caller-supplied, not embedded (see
+ this module's own .mli doc comment on [context] for the fuller
+ rationale, shared with data/ef/sanctoral.sexp). *)
+let context ~lectionary : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
{ Rite.id = Temporal_ef.id;
vocab = Vocab_ef.vocab;
year_start = Temporal_ef.year_start;
@@ -23,4 +32,4 @@ let context : (Vocab_ef.season, Vocab_ef.rank) Rite.t =
admit = Precedence_ef.admit };
season_runs = Vocab_ef.seasons;
transfer_target = Precedence_ef.transfer_target;
- readings = Lectionary_ef.readings }
+ readings = Lectionary_ef.readings ~lectionary }
diff --git a/lib/rites/rite_ef/rite_ef.mli b/lib/rites/rite_ef/rite_ef.mli
index 710db1d..1a4c715 100644
--- a/lib/rites/rite_ef/rite_ef.mli
+++ b/lib/rites/rite_ef/rite_ef.mli
@@ -25,9 +25,10 @@ module Lectionary_ef = Lectionary_ef
- [transfer_target]: {!Precedence_ef.transfer_target}, RG 96 (see that
value's own documentation for the termination and forward-progress
argument {!Colitur_kernel.Rite.t.transfer_target}'s contract requires).
- - [readings]: {!Lectionary_ef.readings} -- the observed celebration's own
- proper, else the day's own temporal slug in data/ef/lectionary.sexp
- (chain steps 1-2; the ferial fallback and the Commons are later work).
+ - [readings]: {!Lectionary_ef.readings} partially applied to the caller's
+ own [~lectionary] -- the observed celebration's own proper, else the
+ day's own temporal slug in data/ef/lectionary.sexp (chain steps 1-2;
+ the ferial fallback and the Commons are later work).
Deliberately carries no [sanctoral]/[lectionary] fields the way the
original design-doc sketch of [RITE] does: {!Colitur_kernel.Rite.t} (the
@@ -35,5 +36,14 @@ module Lectionary_ef = Lectionary_ef
a separate argument to {!Colitur_kernel.Calendar.year}/[day] rather than
embedding it here, so a caller can load data/ef/sanctoral.sexp (plus
data/ef/adjustments.sexp's overlay) however suits it -- bin/main.ml's
- [load_ef_layer] is the one this module ships with. *)
-val context : (Vocab_ef.season, Vocab_ef.rank) Colitur_kernel.Rite.t
+ [load_ef_layer] is the one this module ships with. [~lectionary] here is
+ the exact same discipline (fix round 1, coordinator review: [context]
+ used to be a plain value that loaded data/ef/lectionary.sexp as a side
+ effect of {!Lectionary_ef} being linked, which broke every subcommand
+ that never touches lectionary data at all the moment that file was
+ missing from a bare build -- see the task report). A future
+ diocesan/proper lectionary overlay has a caller-side seam to attach to
+ for the same reason the sanctoral overlay already does. *)
+val context :
+ lectionary:Colitur_kernel.Lectionary.t ->
+ (Vocab_ef.season, Vocab_ef.rank) Colitur_kernel.Rite.t