summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/kernel/precedence.ml3
-rw-r--r--lib/kernel/precedence.mli16
-rw-r--r--lib/kernel/validate.ml17
-rw-r--r--lib/rites/rite_ef/precedence_ef.ml46
-rw-r--r--lib/rites/rite_ef/precedence_ef.mli45
5 files changed, 104 insertions, 23 deletions
diff --git a/lib/kernel/precedence.ml b/lib/kernel/precedence.ml
index 05ad69f..d48203e 100644
--- a/lib/kernel/precedence.ml
+++ b/lib/kernel/precedence.ml
@@ -17,6 +17,7 @@ type ('s, 'r) rules = {
disposition : winner:'r candidate -> loser:'r candidate -> disposition;
admit :
observed:'r candidate ->
+ temporal:'r candidate ->
('r candidate * privilege) list ->
('r candidate * privilege) list;
}
@@ -55,7 +56,7 @@ let resolve rules ctx ~temporal ~sanctoral =
([], [], []) losers
in
let comms = List.rev comms and deferred = List.rev deferred in
- let admitted = rules.admit ~observed comms in
+ let admitted = rules.admit ~observed ~temporal comms in
let dropped =
List.filter (fun c -> not (List.exists (fun a -> fst a == fst c) admitted)) comms
in
diff --git a/lib/kernel/precedence.mli b/lib/kernel/precedence.mli
index ae054dd..d394cb1 100644
--- a/lib/kernel/precedence.mli
+++ b/lib/kernel/precedence.mli
@@ -34,12 +34,28 @@ type ('s, 'r) rules = {
(** RG 92-95: the loser's fate, which depends on the loser's own rank. *)
admit :
observed:'r candidate ->
+ temporal:'r candidate ->
('r candidate * privilege) list ->
('r candidate * privilege) list;
(** RG 108-111: how many commemorations are admitted, and in what order;
anything filtered out here is recorded in {!resolution.omitted}, not
dropped.
+ [temporal] is {!resolve}'s own [~temporal] argument, passed through
+ unchanged -- the day's temporal-cycle candidate, regardless of
+ whether it won. Fix round 1 (RG16(a) task): before this, a rite's
+ [admit] could only infer properties of the CIVIL DAY (chiefly "is
+ this a Sunday", RG 111(b)'s own two-tier admission rule) from
+ [observed]'s own fields -- a proxy that breaks the moment something
+ OTHER than the day's own temporal candidate can be [observed], the
+ exact shape RG 16(a) introduces (a Feast of the Lord standing in
+ the impeded Sunday's place "cum omnibus iuribus et privilegiis",
+ RG 91 entry 14). This is NOT a kernel definition of "Sunday" --
+ the kernel does not gain any rite-specific knowledge by this
+ parameter, it only threads through a value {!resolve} already
+ holds; a rite's own [admit] is free to ignore it entirely, the
+ same as [observed].
+
OBLIGATION ON THE IMPLEMENTATION, not enforced by this type: every
candidate this function returns must be a value taken UNCHANGED
from its input list, never rebuilt (e.g. via a [{ c with ... }]
diff --git a/lib/kernel/validate.ml b/lib/kernel/validate.ml
index cc8bdce..a3208dd 100644
--- a/lib/kernel/validate.ml
+++ b/lib/kernel/validate.ml
@@ -303,11 +303,26 @@ let run (rite : ('s, 'r) Rite.t) (layer : 'r Layer.t) ~year =
let observed_candidate : 'r Precedence.candidate =
{ Precedence.cel = d.Liturgical_day.observed; origin = Precedence.Sanctoral }
in
+ (* [~temporal] (fix round 1, RG16(a) task): {!Precedence.rules.admit}
+ now also takes the day's own temporal-cycle candidate, reused
+ here from {!Liturgical_day.t}'s own embedded [Temporal.t] --
+ the exact same value {!Calendar} passed to {!Precedence.resolve}
+ in the first place, so re-offering is against the SAME inputs,
+ not a reconstruction that could itself introduce a false
+ negative. [origin] is [Precedence.Temporal], genuinely (this IS
+ the temporal candidate, not a reconstructed sanctoral one). *)
+ let temporal_candidate : 'r Precedence.candidate =
+ { Precedence.cel = d.Liturgical_day.temporal.Temporal.office;
+ origin = Precedence.Temporal }
+ in
let as_candidates comms =
List.map (fun (c, p) -> ({ Precedence.cel = c; origin = Precedence.Sanctoral }, p)) comms
in
let offered = as_candidates d.Liturgical_day.commemorations in
- let readmitted = rite.Rite.rules.Precedence.admit ~observed:observed_candidate offered in
+ let readmitted =
+ rite.Rite.rules.Precedence.admit ~observed:observed_candidate
+ ~temporal:temporal_candidate offered
+ in
let norm l =
List.map (fun (c, p) -> (Slug.to_string c.Precedence.cel.Celebration.slug, p)) l
|> List.sort compare
diff --git a/lib/rites/rite_ef/precedence_ef.ml b/lib/rites/rite_ef/precedence_ef.ml
index 179fa13..2987312 100644
--- a/lib/rites/rite_ef/precedence_ef.ml
+++ b/lib/rites/rite_ef/precedence_ef.ml
@@ -707,10 +707,35 @@ let disposition ~(winner : Vocab_ef.rank Precedence.candidate)
classis", "dominicis II classis", "aliis diebus II classis", "diebus III
et IV classis") -- read here off [observed]'s own [rank] and, for the
Sunday/non-Sunday II-class split, the same slug marker [privilege_of] and
- RG 33's [impedes_vigil] already use ([is_sunday_slug]). No [context]
- (date/season/weekday) is available to [admit] (see precedence.mli's
- [rules.admit]) or needed: [observed] IS the day's own celebration, so its
- rank and slug already carry everything RG 111's own four categories test. *)
+ RG 33's [impedes_vigil] already use ([is_sunday_slug]).
+
+ CORRECTED (fix round 1, RG16(a) task): the previous version of this
+ comment claimed "[observed] IS the day's own celebration, so its rank and
+ slug already carry everything RG 111's own four categories test" --
+ WRONG once RG 16(a) exists. RG 16(a)'s own text says the winning Feast of
+ the Lord holds the Sunday's place "cum omnibus iuribus et privilegiis"
+ (with ALL its rights and privileges) -- the day remains a "dominica II
+ classis" for RG 111(b)'s own purposes even though [observed] is now the
+ FEAST, not the Sunday, so [observed]'s own slug is no longer a reliable
+ signal of "is this a Sunday" once something can legitimately observe in
+ the Sunday's place. Confirmed wrong for real data by the oracle: 6 August
+ falling on a Sunday shows the Transfiguration observed and NO
+ commemoration (missalemeum: `commemorations: []`, Pope Sixtus II et al.
+ `displaced`); the pre-fix code, reading Sunday-ness off [observed]'s own
+ slug ("transfiguration-of-our-lord", no Sunday marker), wrongly took the
+ [Class2, false] "other II class: one" branch below and admitted Sixtus
+ (Class3) regardless of RG 111(b)'s own "de festo II classis" rank floor.
+ Control, also oracle-confirmed: 6 August on an ordinary WEEKDAY (no
+ Sunday collision) correctly admits Sixtus -- being a Sunday is exactly
+ what excludes him, and [observed]'s own identity cannot tell the two
+ cases apart on its own.
+
+ Fixed by reading Sunday-ness off [temporal] instead -- {!Precedence.rules.admit}'s
+ own [~temporal] parameter, {!Precedence.resolve}'s [~temporal] argument
+ passed straight through, unaffected by whether it won the day. [context]
+ (date/season/weekday) is still not needed: [temporal]'s own slug already
+ carries everything this split needs, the same way [observed]'s used to
+ before a competing office could occupy the Sunday's place. *)
(* RG 8's four-class dignity order, Class1 highest. Deliberately NOT [band]
(RG 91's much finer 28-entry table): [band] needs a [context] [admit]
@@ -738,6 +763,7 @@ let rec take n = function
| x :: xs -> if n <= 0 then [] else x :: take (n - 1) xs
let admit ~(observed : Vocab_ef.rank Precedence.candidate)
+ ~(temporal : Vocab_ef.rank Precedence.candidate)
(comms : (Vocab_ef.rank Precedence.candidate * Precedence.privilege) list) :
(Vocab_ef.rank Precedence.candidate * Precedence.privilege) list =
(* Sorted once, by dignity then slug (see [compare_dignity]); every branch
@@ -758,11 +784,17 @@ let admit ~(observed : Vocab_ef.rank Precedence.candidate)
let sorted = List.stable_sort compare_dignity comms in
let is_privileged (_, p) = p = Precedence.Privileged in
let observed_rank = observed.Precedence.cel.Celebration.rank in
- let observed_is_sunday =
- is_sunday_slug (Slug.to_string observed.Precedence.cel.Celebration.slug)
+ (* CORRECTED (fix round 1, RG16(a) task): read off [temporal], not
+ [observed] -- see this function's own doc comment above for the full
+ argument and the oracle evidence. [temporal] is the day's own
+ temporal-cycle candidate regardless of who is [observed]; RG 16(a)
+ makes that distinction live for the first time (a Feast of the Lord
+ can now be [observed] on a day whose [temporal] candidate is a Sunday). *)
+ let day_is_sunday =
+ is_sunday_slug (Slug.to_string temporal.Precedence.cel.Celebration.slug)
in
let open Vocab_ef in
- match (observed_rank, observed_is_sunday) with
+ match (observed_rank, day_is_sunday) with
| Class1, _ ->
(* RG 111: "I class: none save one privileged." Ordinary commemorations
never get a slot at all on a I-class day, no matter how many are
diff --git a/lib/rites/rite_ef/precedence_ef.mli b/lib/rites/rite_ef/precedence_ef.mli
index 55f947e..ee7667d 100644
--- a/lib/rites/rite_ef/precedence_ef.mli
+++ b/lib/rites/rite_ef/precedence_ef.mli
@@ -164,24 +164,26 @@ val nativity_octave_prefix : string
so the two cannot silently drift apart. *)
val september_ember_prefix : string
-(** [admit ~observed comms]: RG 108-111 (docs/research/rules-register.md §4,
- "Commemorations"). How many of [comms] -- each already tagged with its
- real RG 109 privilege by {!disposition} -- RG 111 admits, and which,
+(** [admit ~observed ~temporal comms]: RG 108-111 (docs/research/rules-register.md
+ §4, "Commemorations"). How many of [comms] -- each already tagged with
+ its real RG 109 privilege by {!disposition} -- RG 111 admits, and which,
given the day actually observed:
- [observed] a [Class1] day: none, except at most one privileged
commemoration (the highest-dignity one, if several are due) -- an
ordinary one is never admitted here, no matter how many are due;
- - [observed] a [Class2] Sunday (its slug carries {!sunday_marker}): one,
- subject to TWO conditions, not one -- (i) a privileged commemoration,
- whenever due, categorically takes the day's one slot over any
- ordinary one, not by comparing dignity, so an ordinary commemoration
- that would otherwise win on dignity is still dropped; (ii) failing
- that, the slot is reserved for a [Class2] candidate SPECIFICALLY
- ("de festo II classis", RG 111(b)'s own wording -- a RANK FLOOR, not
- "whichever ordinary candidate has the best dignity"): a III- or
- IV-class ordinary loser has no standing for this slot at all and is
- admitted nothing, even when it is the only candidate due;
- - [observed] any other [Class2] day: one, by dignity alone -- no
+ - the CIVIL DAY is a [Class2] Sunday ([temporal]'s slug carries
+ {!sunday_marker} -- CORRECTED, fix round 1, RG16(a) task: read off
+ [temporal], not [observed]; see below): one, subject to TWO
+ conditions, not one -- (i) a privileged commemoration, whenever due,
+ categorically takes the day's one slot over any ordinary one, not by
+ comparing dignity, so an ordinary commemoration that would otherwise
+ win on dignity is still dropped; (ii) failing that, the slot is
+ reserved for a [Class2] candidate SPECIFICALLY ("de festo II classis",
+ RG 111(b)'s own wording -- a RANK FLOOR, not "whichever ordinary
+ candidate has the best dignity"): a III- or IV-class ordinary loser
+ has no standing for this slot at all and is admitted nothing, even
+ when it is the only candidate due;
+ - the civil day is any other [Class2] day: one, by dignity alone -- no
privilege override and no rank floor, unlike the Sunday case
immediately above;
- [observed] a [Class3] or [Class4] day: at most two, by dignity alone.
@@ -192,6 +194,20 @@ val september_ember_prefix : string
Ties break on slug, matching {!Precedence.compare_by}, so the result
never depends on the order [comms] arrives in.
+ [temporal] -- CORRECTED, fix round 1 (RG16(a) task): this function used
+ to read the Sunday/non-Sunday split off [observed]'s own slug, which
+ silently assumed [observed] IS the day's temporal-cycle office. RG 16(a)
+ breaks that assumption on purpose: a Feast of the Lord holds an impeded
+ II-class Sunday's own place "cum omnibus iuribus et privilegiis"
+ (RG 16(a)'s own text), so the day still counts as a "dominica II
+ classis" for RG 111(b) even though [observed] is now the FEAST.
+ [temporal] -- {!Precedence.rules.admit}'s own parameter, the day's
+ temporal-cycle candidate regardless of who won -- is the reliable
+ signal; oracle-confirmed (6 August: Sunday excludes a Class3 saint
+ Sixtus II from the freed slot, an ordinary weekday admits him). Every
+ row of the previous behaviour where [observed] and [temporal] coincide
+ (no RG 16(a) displacement occurred) is unaffected.
+
Every candidate this returns is a value taken unchanged from [comms],
never rebuilt: {!Precedence.resolve}'s own [dropped]/[omitted]
accounting tells an admitted candidate from a dropped one by physical
@@ -202,6 +218,7 @@ val september_ember_prefix : string
itself total over an empty or arbitrarily long [comms]. *)
val admit :
observed:Vocab_ef.rank Precedence.candidate ->
+ temporal:Vocab_ef.rank Precedence.candidate ->
(Vocab_ef.rank Precedence.candidate * Precedence.privilege) list ->
(Vocab_ef.rank Precedence.candidate * Precedence.privilege) list