From ea22ad2bde211998e6719fd5fb76233571a48383 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Wed, 12 Aug 2026 15:16:00 +0200 Subject: fix(kernel,rite-ef): admit orders commemorations by RG 113's table of precedence, not slug Precedence_ef.admit broke a same-rank tie among commemoration candidates alphabetically by slug -- a deterministic engineering convention with no rubrical citation. RG 113's own second sentence, primary-source-verified against two independent scans and previously uncited in the register (only "commemoratio de Tempore fit primo loco" was quoted before), gives the real rule: "in admittendis et ordinandis aliis commemorationibus, servetur ordo tabellae praecedentiae" -- admitting and ordering commemorations both run on the rite's own table of precedence (band's 28-entry table), not RG 8's coarse four-class rank. Precedence.resolve now computes each commemoration candidate's own band value once, generically, and hands it to rules.admit as a third tuple element (Precedence.rules.admit's signature changed accordingly, ditto Precedence_ef.admit; every rule-record stub in the test suite updated to match). Precedence_ef.admit's own compare_dignity is replaced by compare_precedence, ordering by band then slug; a residual tie within one identical band value still falls back to slug, since RG 113 gives no further instruction there -- documented as a still-uncited engineering convention, not dressed up as a rubric. RG 98 ("in paritate autem Officium prius impeditum praecedit") was considered as a candidate authority for that residual and rejected: it governs the transfer queue order among several simultaneously-impeded I-class feasts (Caput XIII), a different operation in a different chapter from RG 113's commemoration admission (Caput XVI); nothing in the primary text connects the two. Blast radius measured against the pre-change binary across the entire 1583-9999 domain (not only 2005-2050): the admitted-commemoration-slug set is byte-identical, day for day, before and after this change. The fix corrects the citation and mechanism, not the answer, on this codebase's current data -- both of the task brief's named examples (22 Feb Chair-of-Peter/Lent-vs-Paul, 22 Sept Maurice-vs-Thomas-of- Villanova) are confirmed present and unchanged in both streams. A new test (RG113: admit picks by precedence order, not slug, when they disagree) proves admit actually consults the passed-in precedence value with a synthetic pair whose slug order and precedence order disagree -- teeth a same-band-only regression test could not have caught, since every real collision found in the domain happens to agree on both axes. 271 -> 272 tests, all green; COLITUR_EXHAUSTIVE_SWEEP=1 unaffected. --- lib/rites/rite_ef/precedence_ef.mli | 58 +++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 21 deletions(-) (limited to 'lib/rites/rite_ef/precedence_ef.mli') diff --git a/lib/rites/rite_ef/precedence_ef.mli b/lib/rites/rite_ef/precedence_ef.mli index ee7667d..49195f9 100644 --- a/lib/rites/rite_ef/precedence_ef.mli +++ b/lib/rites/rite_ef/precedence_ef.mli @@ -166,33 +166,49 @@ val september_ember_prefix : string (** [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: + its real RG 109 privilege by {!disposition}, and its own {!band} value + (RG 91's table-of-precedence entry, computed once by + {!Precedence.resolve} -- see {!Precedence.rules.admit}'s own doc) -- 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; + commemoration (the highest-{!band}-precedence one, if several are + due) -- an ordinary one is never admitted here, no matter how many + are due; - 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. + comparing table position, so an ordinary commemoration that would + otherwise win on table order 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 table position"): 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 {!band}'s table order + alone -- no privilege override and no rank floor, unlike the Sunday + case immediately above; + - [observed] a [Class3] or [Class4] day: at most two, by {!band}'s table + order alone. - "Dignity" here is [Vocab_ef.rank] (RG 8's four classes), NOT {!band}'s - finer RG 91 entry number -- {!band} needs a [context] (date/season/ - weekday) this function does not receive (see {!Precedence.rules.admit}). - Ties break on slug, matching {!Precedence.compare_by}, so the result - never depends on the order [comms] arrives in. + CORRECTED, Task B (branch ef-rg16a): this used to sort by + [Vocab_ef.rank] (RG 8's coarse four-class "dignity") and break same-rank + ties alphabetically by slug -- an engineering convention with no + rubrical warrant, cited nowhere, silently deciding 66 days over + 2005-2050. RG 113's own second sentence, previously uncited + (docs/research/rules-register.md §4's RG 113 entry), is the real rule: + *"in admittendis et ordinandis aliis commemorationibus, servetur ordo + tabellae praecedentiae"* -- admitting and ordering commemorations both + run on {!band}'s own finer RG 91 table, not RG 8's four classes. + {!band} needs a [context] (date/season/weekday) this function does not + receive on its own, so {!Precedence.resolve} computes it once, + generically, and hands each candidate its own value as the trailing + [int] on [comms]'s triples (see {!Precedence.rules.admit}). Ties break + on slug ONLY within one identical [band] value (RG 113 gives no further + instruction there; still an uncited engineering convention, register §6 + "RG 113 tie-break"), matching {!Precedence.compare_by}'s own fallback, + 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 @@ -219,7 +235,7 @@ val september_ember_prefix : string 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 * int) list -> (Vocab_ef.rank Precedence.candidate * Precedence.privilege) list (** The Annunciation's own bootstrapped slug (data/ef/sanctoral.sexp, Task -- cgit v1.3