diff options
Diffstat (limited to 'lib/rites/rite_ef/precedence_ef.ml')
| -rw-r--r-- | lib/rites/rite_ef/precedence_ef.ml | 88 |
1 files changed, 58 insertions, 30 deletions
diff --git a/lib/rites/rite_ef/precedence_ef.ml b/lib/rites/rite_ef/precedence_ef.ml index b9b1731..0feb3e0 100644 --- a/lib/rites/rite_ef/precedence_ef.ml +++ b/lib/rites/rite_ef/precedence_ef.ml @@ -405,9 +405,16 @@ let disposition ~(winner : Vocab_ef.rank Precedence.candidate) branch that completes Task 7's All Souls fix (register line 334, RG 91 entry 8): All Souls is I class, not a vigil, and not a Sunday slug, so once it loses to an occurring Sunday it still reaches here - and transfers -- to 3 November per the register, but WHERE it lands - is Rite.transfer_target's job (RG 96), not this function's; - disposition only says THAT it moves. *) + and transfers -- to 3 November, now DIRECTLY authorised by RG 96 + Attamen (b) (primary-source-verified 2026-08-12): "Commemoratio + omnium Fidelium defunctorum, quando occurrit cum dominica, + transfertur, tamquam in sedem propriam, in feriam II sequentem" -- + when it coincides with a Sunday, transferred, as to its own proper + seat, to the following Monday. Previously this rested only on entry + 8's own parenthetical plus the general RG 96 walk, which happened to + produce the right date; WHERE it lands either way is + Rite.transfer_target's job, not this function's -- disposition only + says THAT it moves. *) Precedence.Transfer else (* RG 95's other branch: "aut commemorantur aut penitus omittuntur" -- @@ -545,14 +552,23 @@ let admit ~(observed : Vocab_ef.rank Precedence.candidate) already draws for RG 111 ({!dignity}, not [band]). *) let is_blocking (rank : Vocab_ef.rank) = rank = Vocab_ef.Class1 || rank = Vocab_ef.Class2 -(* RG 96's own named exception, register-transcribed: "(Annunciation - exception): -> Monday after Low Sunday." Identified by slug -- the same - convention this file already uses to pick out one specific celebration - from a rank/status shape shared by many others ({!nativity_octave_prefix}, - [is_ember_18]'s date anchors) -- not an RG citation itself: RG 96 does not - encode how a computer recognises "the Annunciation", only what happens to - it once recognised. data/ef/sanctoral.sexp's own bootstrapped slug (Task - 10), reused verbatim rather than guessed. *) +(* RG 96's own named exception (docs/research/rules-register.md §4, + "Transfer/translation", RG 96 Attamen (a) -- primary-source-verified + 2026-08-12, corrected from an earlier unconditional transcription; see + the register's own correction note). Verbatim: "festum Annuntiationis + B. Mariae Virg., quando est transferendum post Pascha, transfertur, + tamquam in sedem propriam, in feriam II post dominicam in albis" -- when + [the feast] is to be transferred PAST EASTER, [it] is transferred, as to + its own proper seat, to the Monday after Low Sunday. The exception is + CONDITIONAL on that "past Easter" clause -- {!transfer_target} tests it + by comparing the GENERAL RG 96 target against Easter itself, not by + testing the date here. Identified by slug -- the same convention this + file already uses to pick out one specific celebration from a rank/ + status shape shared by many others ({!nativity_octave_prefix}, + [is_ember_18]'s date anchors) -- not an RG citation itself: RG 96 does + not encode how a computer recognises "the Annunciation", only what + happens to it once recognised. data/ef/sanctoral.sexp's own bootstrapped + slug (Task 10), reused verbatim rather than guessed. *) let annunciation_slug = "annunciation-of-the-blessed-virgin-mary" (* Not an RG citation -- a defensive engineering ceiling, the same role @@ -620,27 +636,39 @@ let rec search_from (occupant : Date.t -> Vocab_ef.rank Celebration.t) (steps : (* [transfer_target]'s contract (rite.mli): total, terminating, and its result is always strictly after [origin]. Terminating: [search_from]'s - own structural bound, above. Strictly after [origin]: the ordinary branch - starts the search at [Date.add_days origin 1] and [search_from] only ever - advances forward from its own starting point, so the result is always >= - origin + 1. The Annunciation branch starts instead at the Monday after - Low Sunday for [origin]'s own civil year -- NOT provably later than - [origin] by the code alone, but true of every representable year: the - Annunciation's [origin] is always 25 March (Date_spec.Fixed in + own structural bound, above. Strictly after [origin]: the general branch + is exactly [search_from]'s own result starting at [Date.add_days origin + 1], which only ever advances forward from there, so it is always >= + origin + 1. The Annunciation branch, when it fires, instead searches from + the Monday after Low Sunday for [origin]'s own civil year -- NOT provably + later than [origin] by the code alone, but true of every representable + year: the Annunciation's [origin] is always 25 March (Date_spec.Fixed in data/ef/sanctoral.sexp), Easter always falls within that SAME civil year in [22 March, 25 April] (Computus's own documented range, register §0), so Low Sunday (Easter + 7) falls in [29 March, 2 May] and the Monday - after it in [30 March, 3 May] -- always after 25 March. *) + after it in [30 March, 3 May] -- always after 25 March. + + RG 96 Attamen (a) (see {!annunciation_slug}'s own comment) makes the + Annunciation exception CONDITIONAL on the general walk carrying the + feast past Easter -- so the general target is always computed FIRST, + for every candidate, and only overridden for the Annunciation when that + target itself falls after Easter Sunday. A version of this function that + tested the DATE of [origin] instead (e.g. "is 25 March within some fixed + window of Easter") would be re-deriving the register's own "quando est + transferendum post Pascha" condition from first principles, exactly the + kind of guess this project's "a wrong citation is worse than a missing + one" rule warns against; comparing the general target against Easter + directly tests the rubric's own words. *) let transfer_target (c : Vocab_ef.rank Precedence.candidate) (origin : Date.t) (occupant : Date.t -> Vocab_ef.rank Celebration.t) : Date.t = - let start = - if Slug.to_string c.Precedence.cel.Celebration.slug = annunciation_slug then - (* Low Sunday = Easter + 7 (register §0, temporal_ef.ml's [off 7]); the - Monday after it = Easter + 8. Searched onward from there exactly - like the general case searches from [origin + 1] -- "only if that - day is itself blocked" (rite.mli) is [search_from]'s ordinary - behaviour, not a second mechanism. *) - Date.add_days (Computus.gregorian_easter (Date.year origin)) 8 - else Date.add_days origin 1 - in - search_from occupant 0 start + let general_target = search_from occupant 0 (Date.add_days origin 1) in + let is_annunciation = Slug.to_string c.Precedence.cel.Celebration.slug = annunciation_slug in + let easter = Computus.gregorian_easter (Date.year origin) in + if is_annunciation && Date.compare general_target easter > 0 then + (* Low Sunday = Easter + 7 (register §0, temporal_ef.ml's [off 7]); the + Monday after it = Easter + 8. Searched onward from there exactly + like the general case searches from [origin + 1] -- "only if that + day is itself blocked" (rite.mli) is [search_from]'s ordinary + behaviour, not a second mechanism. *) + search_from occupant 0 (Date.add_days easter 8) + else general_target |
