summaryrefslogtreecommitdiff
path: root/tools/bootstrap_lectionary.ml
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bootstrap_lectionary.ml')
-rw-r--r--tools/bootstrap_lectionary.ml159
1 files changed, 150 insertions, 9 deletions
diff --git a/tools/bootstrap_lectionary.ml b/tools/bootstrap_lectionary.ml
index 52c7e50..a4c82ae 100644
--- a/tools/bootstrap_lectionary.ml
+++ b/tools/bootstrap_lectionary.ml
@@ -52,12 +52,67 @@ let parse_ini path =
close_in ic;
List.rev !sections
+(* Task 8 (branch ef-lectionary, differential fix round): lectio's own ini
+ section names are NOT always the slug {!Rite_ef.Temporal_ef} computes
+ for the IDENTICAL office. Confirmed the hard way: the first version of
+ this generator carried section names through {!Slug.of_string}
+ verbatim, so the data these renamed families need was sitting in this
+ very file all along -- under lectio's spelling -- while
+ [Lectionary_ef.readings]' step 2 looked it up under colitur's own,
+ found nothing, and silently fell through to step 3's ferial-resumption
+ answer instead. Invisible until test/test_differential.ml first
+ compared citation CONTENT (this task): a day's SLUG/rank/colour already
+ matched, so nothing before this task ever noticed the READING was
+ wrong. [colitur_keys] is the closed translation table -- the SAME
+ families test/test_differential.ml's own Layer A ([norm_slug]) already
+ established as pure vocabulary, carrying no liturgical substance, not
+ re-derived here. Kept in the generator, not in [Lectionary_ef.readings]
+ itself, because a bootstrap step exists exactly to translate an
+ external vocabulary into colitur's own ONCE, at data-generation time --
+ baking an alias table into the rite's own runtime lookup would just
+ move the vocabulary problem, not solve it.
+
+ A translation can widen ONE ini section into several colitur keys
+ (Passiontide: lectio never distinguishes Passion week from Holy week at
+ the slug level, "ef-passiontide-0-<weekday>" for both -- confirmed
+ empirically, its OWN computed reading is byte-identical between the two
+ weeks' same weekday throughout 2005-2050 -- so both of colitur's own
+ week-specific keys legitimately point at the one source entry); it
+ never narrows or drops one, and every key not named here passes through
+ unchanged (e.g. "ef-easter-8-{monday,tuesday,thursday}", the three
+ non-Ember Pentecost-octave ferias colitur does NOT rename). *)
+let weekdays = [ "monday"; "tuesday"; "wednesday"; "thursday"; "friday"; "saturday" ]
+
+let colitur_keys name =
+ if String.equal name "ef-christmas-sunday-0" then
+ (* WIDEN, not rename -- fix round (found by test_lectionary_ef.ml's own
+ pre-existing test_step3_christmas_feria_resumes_sunday going from
+ PASS to FAIL): "ef-christmas-sunday-0" is not only lectio's own
+ calendar-level slug for RG 17(a)'s Holy Name Sunday
+ (test_differential.ml's own [norm_slug] comment) -- it is ALSO
+ colitur's own GENUINE, DIRECTLY-COMPUTED temporal slug (Rite_ef.
+ Temporal_ef.temporal, "if m = 12 && dd >= 26 then Some
+ \"ef-christmas-sunday-0\"") for an ordinary Sunday landing on 26-28
+ December, the historical "Sunday within the Octave of the Nativity"
+ -- a DIFFERENT civil window than Holy Name Sunday (2-5 January), and
+ Missal-confirmed (docs/research/scan1.txt, "Dominica infra octavam
+ Nativitatis Domini, II classis") to be the IDENTICAL Mass (Gal.
+ 4,1-7 / Luc. 2,33-40), not a coincidence. The first version of this
+ translation REPLACED the key outright and broke that pre-existing,
+ working case -- caught by the existing test suite, not by this
+ generator's own reasoning; keeping the original key alongside the
+ Holy-Name-Sunday alias fixes it, following the same "widen, never
+ narrow" rule Passiontide below already established. *)
+ [ "ef-christmas-sunday-0"; "ef-holy-name-sunday" ]
+ else if String.equal name "ef-easter-8-wednesday" then [ "ef-pentecost-ember-wed" ]
+ else if String.equal name "ef-easter-8-friday" then [ "ef-pentecost-ember-fri" ]
+ else if String.equal name "ef-easter-8-saturday" then [ "ef-pentecost-ember-sat" ]
+ else (
+ match List.find_opt (fun wd -> String.equal name ("ef-passiontide-0-" ^ wd)) weekdays with
+ | Some wd -> [ "ef-passiontide-1-" ^ wd; "ef-passiontide-2-" ^ wd ]
+ | None -> [ name ])
+
let convert sec =
- let slug =
- match Slug.of_string sec.name with
- | Ok s -> s
- | Error e -> die "bad slug %S: %s" sec.name e
- in
let cite part key =
match List.assoc_opt key sec.fields with
| None | Some "" -> None
@@ -69,7 +124,86 @@ let convert sec =
die "%s: has one reading, not two -- an Epistle without a Gospel (or the \
reverse) is malformed and must be investigated, not silently shipped"
sec.name;
- (slug, cs)
+ List.map
+ (fun key ->
+ match Slug.of_string key with
+ | Ok slug -> (slug, cs)
+ | Error e -> die "bad slug %S (translated from %S): %s" key sec.name e)
+ (colitur_keys sec.name)
+
+(* [ef-nativity-vigil] (RG 91 entry 5, {!Rite_ef.Temporal_ef}'s own [named])
+ is a TEMPORAL office with no section of its own in THIS ini at all --
+ lectio computes ITS citations from a different source file entirely,
+ its SANCTORAL calendar (tridentine-calendar.ini's own
+ "[vigil-of-christmas]" section: "reading.first = Rom 1:1-6",
+ "reading.gospel = Matt 1:18-21"). colitur's own sanctoral bootstrap
+ (Task 3) already carried those identical citations onto
+ data/ef/sanctoral.sexp's own `vigil-of-christmas` entry -- inert there
+ because data/ef/adjustments.sexp suppresses it (that overlay's own
+ comment: the SAME celebration as this temporal office, not a second
+ one) -- which corroborates this value independently rather than merely
+ asserting it. Hand-authored here, the same discipline
+ data/ef/adjustments.sexp's own RG 110 companion and Major Litanies
+ `Add` directives already use for a genuine upstream-source gap this
+ generator's own single-ini design cannot reach on its own. *)
+let vigil_entries =
+ [ ( (match Slug.of_string "ef-nativity-vigil" with Ok s -> s | Error e -> die "%s" e),
+ [ { Citation.part = Citation.First; reference = "Rom 1:1-6" };
+ { Citation.part = Citation.Gospel; reference = "Matt 1:18-21" } ] )
+ ]
+
+(* One more colitur-only slug, DERIVED from [ef-holy-name-sunday]'s own
+ citations (just translated above) rather than a second hand-typed copy
+ of the same text: [ef-holy-name] is RG 17(a)'s own fallback ("secus die
+ 2 ianuarii", 2 January in a year with no Sunday 2-5 January). The
+ calendarium's own table (data/ef/expected-divergences.sexp's own C16
+ note quotes it) gives ONE heading for both the Sunday and the fallback
+ shape -- the identical Mass, not two -- so this is the same citation
+ pair, not an independent lookup. Safe to hard-wire (unlike a step-3
+ fallback, which would walk back into a DIFFERENT, unrelated Sunday of
+ the OLD liturgical year): RG 17(a)'s whole point is that this Mass is
+ said in place of, not alongside, whatever ferial reading a bare
+ fallback would otherwise find.
+
+ REJECTED, and recorded so it is not re-attempted: giving
+ [ef-nativity-octave-day-{5,6,7}] (29-31 December, RG 91 entry 17) this
+ SAME derived value too. Tried, then measured against the real
+ differential and REVERTED -- it is wrong. lectio's own citation for
+ those three dates is NOT uniform across years (confirmed against the
+ fixture: 2005-12-29 reads "Heb 1:1-12"/"John 1:1-14", 2006-12-29 reads
+ "1 Cor. 4:1-5"/"Luke 3:1-6" -- two different Masses, not one). Read
+ against the Missal directly (docs/research/scan1.txt, "Dominica infra
+ octavam Nativitatis Domini, II classis": Epistle "Gal. 4, 1-7", Gospel
+ "Luc. 2, 33-40" -- the SAME pair as Holy Name Sunday, corroborating the
+ guess would have been right ONLY for that specific case): the two
+ observed fixture values are each the PREVIOUS true civil Sunday's OWN
+ Mass -- Christmas Day itself (25 Dec 2005 was a Sunday that year:
+ "In Nativitate Domini... Missa in die", Heb 1:1-12/John 1:1-14) or, in
+ a year with no Sunday between Christmas and New Year at all, all the
+ way back to Advent IV (24 Dec 2006 was a Sunday; 1 Cor. 4:1-5/Luke
+ 3:1-6 is that Mass's own citation, already in [ef-advent-sunday-4]
+ above). colitur's OWN existing step 3 ([Lectionary_ef.readings], NOT
+ this generator) already walks back to the true PRECEDING CIVIL Sunday
+ regardless of season and would find EXACTLY these same answers on its
+ own -- a hard-wired entry here would have SHORT-CIRCUITED that correct,
+ already-general mechanism with one wrong, uniform guess. Left absent
+ deliberately: these three dates stay whatever step 3 resolves through
+ [ef-advent-sunday-4]/[ef-holy-name-sunday] et al, or [] on a date whose
+ own preceding Sunday has no entry either (data/ef/expected-
+ divergences.sexp's own C21 entry records what remains, if anything,
+ after that). *)
+let derived_entries entries =
+ let holy_name_sunday_citations =
+ match
+ List.find_opt (fun (s, _) -> String.equal (Slug.to_string s) "ef-holy-name-sunday") entries
+ with
+ | Some (_, cs) -> cs
+ | None ->
+ die "internal: ef-holy-name-sunday missing after translation -- cannot derive its dependants"
+ in
+ match Slug.of_string "ef-holy-name" with
+ | Ok s -> [ (s, holy_name_sunday_citations) ]
+ | Error e -> die "%s" e
let sha256 path =
let ic = Unix.open_process_in (Printf.sprintf "sha256sum %s" (Filename.quote path)) in
@@ -81,7 +215,8 @@ let () =
let src = if Array.length Sys.argv > 1 then Sys.argv.(1) else default_source in
let dst = if Array.length Sys.argv > 2 then Sys.argv.(2) else default_dest in
let secs = parse_ini src in
- let entries = List.map convert secs in
+ let translated = List.concat_map convert secs in
+ let entries = translated @ vigil_entries @ derived_entries translated in
let lect =
match Lectionary.of_entries entries with
| Ok l -> l
@@ -96,9 +231,15 @@ let () =
;\n\
; Source: %s\n\
; SHA-256: %s\n\
- ; %d entries. Regenerate with:\n\
+ ; %d entries (%d ini sections translated/widened into colitur's own\n\
+ ; Temporal_ef vocabulary via [colitur_keys]; %d hand-authored from a\n\
+ ; second source file [vigil_entries]; %d derived from an already-\n\
+ ; translated entry above rather than re-typed [derived_entries] --\n\
+ ; see this generator's own comments on all three). Regenerate with:\n\
; eval $(opam env) && dune exec tools/bootstrap_lectionary.exe -- %s %s\n"
- src (sha256 src) (List.length entries) src dst;
+ src (sha256 src) (List.length entries) (List.length secs) (List.length vigil_entries)
+ (List.length entries - List.length translated - List.length vigil_entries)
+ src dst;
Sexplib.Sexp.output_hum oc (Lectionary.sexp_of_t lect);
output_char oc '\n';
close_out oc;