diff options
Diffstat (limited to 'lib/render/view.ml')
| -rw-r--r-- | lib/render/view.ml | 88 |
1 files changed, 81 insertions, 7 deletions
diff --git a/lib/render/view.ml b/lib/render/view.ml index 67dfa70..0b122a7 100644 --- a/lib/render/view.ml +++ b/lib/render/view.ml @@ -54,6 +54,43 @@ let citation_ref ~sigla cits part = | Some c -> Sigla.format sigla c.K.Citation.reference | None -> "" +(* W5: the day's own reading citations, keyed by [Citation.part_to_string] + and restricted to the parts THIS DAY ACTUALLY CARRIES -- generalises what + used to be exactly two hardcoded fields ([first]/[gospel]). A day with + [[First; Second; Gospel]] (OF, a Sunday or solemnity, OLM 1981 + Praenotanda n. 69.1/n. 84(b)(c)) now exposes all three keys; a day with + [[First; Gospel]] (OF ferias/feasts/memorials, n. 66.1; every EF day, + unconditionally, RG-cited lectionary) exposes exactly the two it always + did. [K.Citation.all_parts] order (not [cits]' own order) makes the + result deterministic regardless of how the rite built the list. + + An ABSENT part contributes NO KEY at all, not a present key holding the + empty string -- deliberately, for two independent reasons, not one: + (1) [Template.render]'s own documented contract already makes the two + indistinguishable at every place a template can observe them ([Var], + [Section], [Inverted] -- [Template.truthy] treats [Str ""] and a lookup + miss identically), so nothing is lost expressively; (2) {!Emit_json.year} + dumps this whole [Obj] verbatim, with no field list of its own to filter + through (unlike [Emit_csv]/[Emit_xml]/[Emit_ics], each of which names its + fields explicitly). [Citation.all_parts] also lists [Psalm]/[Tract]/ + [Alleluia]/[Sequence] -- deliberately unbuilt by every rite that exists + today (no source, no oracle, CLAUDE.md) -- and NO rite will ever populate + them, so a present-but-always-empty key for each would sit in every EF + day's JSON forever. Filtering to only the PRESENT parts is what makes EF's + output identical byte for byte across every emitter, [Emit_json] included, + BY CONSTRUCTION rather than by a rite check here: EF's [citations] is + always exactly [[First; Gospel]] ({!Rite_ef}'s own [citation_shapes], + {!Colitur_kernel.Validate}'s "citations" check), so the derived key set + below is always {"first"; "gospel"}, in that order -- letter-for-letter + what the two fields this replaces used to produce. *) +let citation_fields ~sigla cits = + List.filter_map + (fun part -> + match citation_ref ~sigla cits part with + | "" -> None + | s -> Some (K.Citation.part_to_string part, str s)) + K.Citation.all_parts + (* A commemoration's own name resolves through the SAME [lang.celebration] table as the observed day's -- a commemoration's slug is drawn from the identical sanctoral/temporal pool, not a second vocabulary. Templates @@ -74,6 +111,18 @@ let comm_value ~lang (c, priv) = so a template can render it blank. Every field a real day has is present and empty, so a template never hits a missing key on a padding cell -- the same key SET as [day_value], not merely the same shape by coincidence. *) +(* [first]/[gospel] stay a fixed pair here, deliberately NOT derived through + [citation_fields] (there is no day, hence no [citations] list, to derive + from): they mirror the closed set every rite CURRENTLY REACHABLE through + this whole grid/booklet path (EF alone -- [bin/main.ml]'s + [reject_rite_for] refuses [--rite] on every command that calls + [of_days]) always carries. A day with a [Second] reading can only enter a + grid once a rite whose [citation_shapes] includes it is admitted to + these commands -- not built yet, tracked as debt rather than + pre-built, CLAUDE.md's own "one field short of the remedy" discipline -- + at which point this list needs the matching key added, or + [test_padding_and_real_share_key_set] (test_view.ml) will catch the + mismatch immediately. *) let padding_cell dow = T.Obj [ ("iso", str ""); ("dom", str ""); ("dow", str (string_of_int dow)); @@ -100,7 +149,7 @@ let day_value ~lang ~sigla ~vocab (d : ('s, 'r) K.Liturgical_day.t) = let colour_s = K.Colour.to_string colour in let season_s = vocab.K.Vocab.season_to_string tmp.K.Temporal.season in T.Obj - [ ("iso", str (K.Date.to_iso8601 date)); + ([ ("iso", str (K.Date.to_iso8601 date)); ("dom", str (string_of_int (K.Date.day date))); ("dow", str (string_of_int (dow_int (K.Date.weekday date)))); ("in_month", bool true); @@ -138,11 +187,10 @@ let day_value ~lang ~sigla ~vocab (d : ('s, 'r) K.Liturgical_day.t) = T.Obj [ ("slug", str (K.Slug.to_string c.K.Celebration.slug)); ("to", str (K.Date.to_iso8601 dest)) ]) - d.K.Liturgical_day.transferred_out) ); - ("first", str (citation_ref ~sigla d.K.Liturgical_day.citations K.Citation.First)); - ("gospel", str (citation_ref ~sigla d.K.Liturgical_day.citations K.Citation.Gospel)); - (* overwritten per grid row by [set_last]; false in the flat [days] list *) - ("last", bool false) ] + d.K.Liturgical_day.transferred_out) ) ] + @ citation_fields ~sigla d.K.Liturgical_day.citations + @ [ (* overwritten per grid row by [set_last]; false in the flat [days] list *) + ("last", bool false) ]) (* Bucket a month's day values into Sunday-started weeks of exactly seven cells, padding both ends. This is the computation the template cannot do. *) @@ -235,7 +283,33 @@ let weeks_of_month ~first_dow ~month_num ~month_name ~month_abbr day_values = template edit. The key list is the vocabulary's own fixed, closed set (lang/*.ini's own [term] section, Task 1/3) -- not open like [celebration], so it is named here rather than invented a second time from a wildcard - enumeration. *) + enumeration. + + W5 judgment call: ["epistle"] (and, less obviously, ["lesson"] -- the + 1962 Missal's own word for a non-apostolic reading, e.g. an Ember day's + Old Testament reading, as opposed to "Epistola" proper; see + [tools/bootstrap_lectionary.ml]'s "last lesson before the Gospel" + comments) ARE genuinely EF/Roman vocabulary sitting in this otherwise + rite-agnostic list, the same category CLAUDE.md's "carried into Plan 4" + section already tracks for [validate.ml]/[Liturgical_day.transferred_in]/ + [Precedence.privilege]/[Repose]. Left UNCHANGED here rather than made + rite-supplied or renamed, for a reason specific to this key rather than a + blanket "not worth it": nothing FORCES the fix yet. + [bin/main.ml]'s [reject_rite_for] refuses [--rite] on every command that + reaches [term_value] (`table`/`emit`/`render`/`publish`), so OF cannot + reach a template that reads [term.epistle] today, and no OF template + exists under [templates/] to need a different word (only [templates/ef/] + does, and every one of them already reads [term.epistle]). Renaming it + would be a breaking change to those 11 shipped templates AND to any + user's own template, for zero present behavioural difference -- exactly + the trade [Rite.t.citation_shapes]'s own doc comment warns a template-key + rename always is. ["lesson"] already sits unused by any shipped template, + is already translated in both [lang/en.ini] ("Lesson") and [lang/la.ini] + ("Lectio"), and is the natural neutral term a future OF ordo template + would reach for -- so the infrastructure an eventual fix needs already + exists; only the forcing function (OF actually reaching this command) is + missing. Recorded here as the next instance of the pattern rather than + fixed speculatively, matching CLAUDE.md item 8's own discipline. *) let term_keys = [ "ordo"; "contents"; "epistle"; "lesson"; "gospel"; "commemoration"; "week" ] let term_value lang = T.Obj (List.map (fun k -> (k, str (Lang.term lang k))) term_keys) |
