diff options
Diffstat (limited to 'test/test_precedence_ef.ml')
| -rw-r--r-- | test/test_precedence_ef.ml | 158 |
1 files changed, 119 insertions, 39 deletions
diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml index facf3eb..52de989 100644 --- a/test/test_precedence_ef.ml +++ b/test/test_precedence_ef.ml @@ -290,7 +290,7 @@ let test_all_souls_yields_to_sunday () = let rules = { P.band = (fun c cd -> PE.band c cd); disposition = (fun ~winner:_ ~loser:_ -> P.Omit); - admit = (fun ~observed:_ cs -> cs) } + admit = (fun ~observed:_ ~temporal:_ cs -> cs) } in let resolution = P.resolve rules day_ctx ~temporal:sunday ~sanctoral:[ all_souls ] in Alcotest.(check string) "the Sunday is observed, not All Souls" @@ -812,31 +812,58 @@ let observed_class3 = cand ~rank:V.Class3 "ef-some-class3-day" let slugs_of admitted = List.map (fun (c, _) -> S.to_string c.P.cel.Cel.slug) admitted +(* Real-data shapes for the fix round's own RG16(a)/[admit] interaction + (below): a Feast of the Lord (subject Lord, Class2, sanctoral) as + [observed], oracle-confirmed real slugs/ranks rather than hand-typed + ones, the same coupling-safety reason [of_temporal] rows elsewhere in + this file use real data. *) +let lord_winner = + cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Lord ~layer:PE.universal_layer + "transfiguration-of-our-lord" + +(* Pope Sixtus II et al. (6 August, real slug/rank/status from + data/ef/sanctoral.sexp): Class3, Commemoration_only, tagged [Ordinary] + here directly (as every other [admit_cases] row does, isolating + [admit]'s own selection logic from [privilege_of], per this table's own + header comment). *) +let sixtus = + cand ~origin:P.Sanctoral ~rank:V.Class3 ~status:Cel.Commemoration_only + ~layer:PE.universal_layer "pope-sixtus-ii-felicissimus-and-agapitus-martyrs" + +(* (description, observed, temporal, comms, expected). [temporal] -- + {!Precedence.rules.admit}'s own new parameter, fix round 1 (RG16(a) + task): the day's temporal-cycle candidate, independent of who is + [observed]. Every row below except the last two repeats [observed] as + [temporal] -- no RG16(a) displacement occurs in those rows (the pattern + [PE.admit]'s pre-fix code implicitly, and wrongly, assumed held + UNIVERSALLY), so the two values coinciding is the faithful shape, not a + simplification that dodges the new parameter. The last two rows are + where they genuinely differ -- see their own comment. *) let admit_cases = [ (* RG 111 (§4): "I class: none save one privileged." *) ( "I-class day, only an ordinary commemoration due -> none admitted", - observed_class1, + observed_class1, observed_class1, [ (ordinary_hi, P.Ordinary) ], [] ); ( "I-class day, ordinary + privileged both due -> only the privileged \ one, regardless of the ordinary one's higher dignity", - observed_class1, + observed_class1, observed_class1, [ (ordinary_hi, P.Ordinary); (privileged_lo, P.Privileged) ], [ "ef-privileged-lo" ] ); ( "I-class day, two privileged due -> only the higher-dignity one (still \ just \"one\")", - observed_class1, + observed_class1, observed_class1, [ (privileged_lo, P.Privileged); (privileged_hi, P.Privileged) ], [ "ef-privileged-hi" ] ); (* RG 111: "II-class Sundays: one (dropped if a privileged one is due)." *) ( "II-class Sunday, only an ordinary commemoration due -> it is admitted", - observed_class2_sunday, + observed_class2_sunday, observed_class2_sunday, [ (ordinary_hi, P.Ordinary) ], [ "ef-ordinary-hi" ] ); ( "II-class Sunday, ordinary (higher dignity) + privileged (lower \ dignity) both due -> the PRIVILEGED one is admitted, the ordinary \ one dropped despite outranking it", - observed_class2_sunday, + observed_class2_sunday, observed_class2_sunday, [ (ordinary_hi, P.Ordinary); (privileged_lo, P.Privileged) ], [ "ef-privileged-lo" ] ); (* RG 111(b)'s own rank floor ("scilicet DE FESTO II CLASSIS"), fix @@ -848,7 +875,7 @@ let admit_cases = below, which has no such restriction. *) ( "II-class Sunday, sole candidate is an ORDINARY Class3 (not \ \"de festo II classis\") -> admitted nothing, not the best available", - observed_class2_sunday, + observed_class2_sunday, observed_class2_sunday, [ (ordinary_class3, P.Ordinary) ], [] ); (* RG 111: "other II class: one" -- no privilege override, the exact @@ -857,23 +884,55 @@ let admit_cases = observed day, OPPOSITE winner. *) ( "other II-class day, only an ordinary commemoration due -> it is \ admitted", - observed_class2_other, + observed_class2_other, observed_class2_other, [ (ordinary_hi, P.Ordinary) ], [ "ef-ordinary-hi" ] ); ( "other II-class day, same ordinary+privileged pair as the Sunday row \ above -> the ORDINARY one wins on pure dignity this time, the \ privileged one dropped", - observed_class2_other, + observed_class2_other, observed_class2_other, [ (ordinary_hi, P.Ordinary); (privileged_lo, P.Privileged) ], [ "ef-ordinary-hi" ] ); (* RG 111: "III-IV class: at most two" -- three candidates due, top two by dignity admitted, the third (lowest dignity) dropped. *) ( "III-class day, three commemorations due -> the top two by dignity, \ not merely \"two of them\"", - observed_class3, + observed_class3, observed_class3, [ (ordinary_hi, P.Ordinary); (privileged_lo, P.Privileged); (ordinary_lowest, P.Ordinary) ], - [ "ef-ordinary-hi"; "ef-privileged-lo" ] ) + [ "ef-ordinary-hi"; "ef-privileged-lo" ] ); + (* Fix round 1, item 2 (RG16(a) task review): the CRITICAL witness for + [~temporal]. RG 16(a)'s own text -- the winning Feast of the Lord + holds the Sunday's place "cum omnibus iuribus et privilegiis" -- means + the day is STILL a "dominica II classis" for RG 111(b)'s own rank + floor, even though [observed] is now the FEAST (Transfiguration, real + slug/rank/subject), not the Sunday. [temporal] (a real Sunday + candidate, {!an_ordinary_sunday}) is what reveals that; nothing in + [observed] does, since its own slug carries no Sunday marker at all. + Oracle-confirmed (missalemeum, 2023-08-06, a Sunday): + "commemorations": [], Sixtus "displaced". Before this fix + [observed_is_sunday] read [observed]'s own slug and got [false] here, + wrongly taking the "other II class: one" branch below and admitting + Sixtus (Class3) despite RG 111(b)'s rank floor. *) + ( "RG16(a) interaction: a Feast of the Lord observed on a day whose \ + TEMPORAL candidate is a II-class Sunday -> the RG111(b) rank floor \ + still applies, admits nothing (Sixtus, Class3, has no standing)", + lord_winner, an_ordinary_sunday, + [ (sixtus, P.Ordinary) ], + [] ); + (* The control, same pair as the row above with [observed] = [temporal] + (no displacement -- an ordinary WEEKDAY, not a Sunday): "other II + class: one", no rank floor, Sixtus IS admitted. Oracle-confirmed + (missalemeum, 2026-08-06, a Thursday): Sixtus in "commemorations". + Proves the DISCRIMINATING factor is [temporal]'s own Sunday-ness, not + merely "was the winner a Feast of the Lord" -- that alone is true of + BOTH rows here, and only one of them excludes Sixtus. *) + ( "control: the same Feast of the Lord on an ORDINARY weekday (temporal \ + = observed, not a Sunday) -> \"other II class: one\", Sixtus IS \ + admitted", + lord_winner, lord_winner, + [ (sixtus, P.Ordinary) ], + [ "pope-sixtus-ii-felicissimus-and-agapitus-martyrs" ] ) ] (* Order independence (brief: "the admitted set must not depend on input @@ -886,8 +945,10 @@ let test_admit_order_independent () = let comms = [ (ordinary_hi, P.Ordinary); (privileged_lo, P.Privileged); (ordinary_lowest, P.Ordinary) ] in - let forward = slugs_of (PE.admit ~observed:observed_class3 comms) in - let reversed = slugs_of (PE.admit ~observed:observed_class3 (List.rev comms)) in + let forward = slugs_of (PE.admit ~observed:observed_class3 ~temporal:observed_class3 comms) in + let reversed = + slugs_of (PE.admit ~observed:observed_class3 ~temporal:observed_class3 (List.rev comms)) + in Alcotest.(check (list string)) "reversed input admits the same candidates" forward reversed @@ -1023,25 +1084,34 @@ let test_ii_class_sunday_privileged_witness_admitted_end_to_end () = (List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted) (* RG 16(a) (register §6.0) reached end-to-end through the REAL pipeline - ([PE.band] AND [PE.disposition] together, not [disposition] in - isolation as [disposition_cases]'s own rows above test it): a real civil - date this task's own blast-radius measurement names as a live instance - of the bug this branch fixes -- 6 August 2028 is a Sunday (independently - checked with `date -d 2028-08-06 +%A`, the same cross-check discipline - [test_golden.ml]'s own header requires), Time after Pentecost week 9, and - the Transfiguration (6 Aug, II class, "IN TRANSFIGURATIONE D. N. I. C.") - falls on it. Before this fix `colitur day` emitted this Sunday as an - admitted [+ef-time-after-pentecost-sunday-9] commemoration on that date - (register §6.0's own reproduction); this proves the full pipeline now - agrees with the isolated [disposition] rows above: [observed] is the + ([PE.band], [PE.disposition] AND [PE.admit] together, not any one of + them in isolation as this file's own hand-tagged rows test them + separately): a real civil date this task's own blast-radius measurement + names as a live instance of the bug this branch fixes -- 6 August 2028 + is a Sunday (independently checked with `date -d 2028-08-06 +%A`, the + same cross-check discipline [test_golden.ml]'s own header requires), + Time after Pentecost week 9, and the Transfiguration (6 Aug, II class, + "IN TRANSFIGURATIONE D. N. I. C.") falls on it. Before this fix + `colitur day` emitted this Sunday as an admitted + [+ef-time-after-pentecost-sunday-9] commemoration on that date (register + §6.0's own reproduction). + + Fix round 1 (item 2): a THIRD candidate, Pope Sixtus II et al. (real + slug/rank/status, 6 August, unrelated to the Sunday), is now also + offered, so this test exercises BOTH fixes at once, the same real shape + [test_golden.ml]'s own 2028-08-06 pin does: [observed] is the Transfiguration ({!band} entry 14 already did this correctly before this - task), [commemorations] is EMPTY (not merely missing the Sunday from - [admit]'s cut -- RG 16(a) is a [disposition]-level Omit, before [admit] - ever runs), and the Sunday appears in [omitted] with - ["omitted: yielded to a higher day"] ({!Precedence.resolve}'s own Omit - reason), never ["omitted: admission limit reached"] (that reason would - mean the Sunday was tagged [Commemorate] and then cut by [admit] -- a - different, wrong mechanism for the same wrong end state). *) + task); the Sunday is [disposition]-level [Omit] (RG 16(a)); Sixtus is + [disposition]-level [Commemorate], but [admit] then excludes him too -- + RG 111(b)'s rank floor, reached only because [admit] reads the day's + Sunday-ness off [~temporal] (the [sunday] candidate passed to + [P.resolve]), not off [observed] (the Transfiguration, whose own slug + carries no Sunday marker). [commemorations] is EMPTY, and BOTH losers + land in [omitted] with their own distinct reasons -- the Sunday via + [disposition]'s own Omit ("omitted: yielded to a higher day"), Sixtus via + [admit]'s cut ("omitted: admission limit reached") -- proving the two + fixes operate through genuinely different mechanisms, not the same one + coincidentally producing the same string. *) let test_rg16a_lord_feast_suppresses_sunday_end_to_end () = let date = mk 2028 8 6 in let day_ctx = ctx date in @@ -1050,15 +1120,25 @@ let test_rg16a_lord_feast_suppresses_sunday_end_to_end () = cand ~origin:P.Sanctoral ~rank:V.Class2 ~subject:Sub.Lord ~layer:PE.universal_layer "transfiguration-of-our-lord" in - let resolution = P.resolve real_rules day_ctx ~temporal:sunday ~sanctoral:[ transfiguration ] in + let sixtus = + cand ~origin:P.Sanctoral ~rank:V.Class3 ~status:Cel.Commemoration_only ~layer:PE.universal_layer + "pope-sixtus-ii-felicissimus-and-agapitus-martyrs" + in + let resolution = + P.resolve real_rules day_ctx ~temporal:sunday ~sanctoral:[ transfiguration; sixtus ] + in Alcotest.(check string) "the Transfiguration is observed, not the Sunday" "transfiguration-of-our-lord" (S.to_string resolution.P.observed.P.cel.Cel.slug); - Alcotest.(check int) "no commemorations at all -- RG16(a)'s own \"nulla fit commemoratio\"" + Alcotest.(check int) + "no commemorations at all -- RG16(a)'s own \"nulla fit commemoratio\" AND RG111(b)'s rank floor, both live" 0 (List.length resolution.P.commemorations); Alcotest.(check (list (pair string string))) - "the Sunday is omitted with RG16(a)'s own disposition-level reason, not admit's cut" - [ ("ef-time-after-pentecost-sunday-9", "omitted: yielded to a higher day") ] - (List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted) + "both losers omitted, via two DIFFERENT mechanisms: the Sunday at disposition-level (RG16a), Sixtus at \ + admit's own cut (RG111b)" + [ ("ef-time-after-pentecost-sunday-9", "omitted: yielded to a higher day"); + ("pope-sixtus-ii-felicissimus-and-agapitus-martyrs", "omitted: admission limit reached") ] + (List.map (fun (c, reason) -> (S.to_string c.P.cel.Cel.slug, reason)) resolution.P.omitted + |> List.sort compare) (* Completes Task 7's carried fix (RG 91 entry 8, §4): on a real Sunday landing on 2 November, All Souls does not merely lose (that was Task 7's @@ -1091,7 +1171,7 @@ let test_all_souls_transfers_end_to_end () = origin = P.Temporal } in let all_souls = cand ~origin:P.Sanctoral ~layer:PE.universal_layer "ef-all-souls" in - let rules = { P.band = PE.band; disposition = PE.disposition; admit = (fun ~observed:_ cs -> cs) } in + let rules = { P.band = PE.band; disposition = PE.disposition; admit = (fun ~observed:_ ~temporal:_ cs -> cs) } in let resolution = P.resolve rules day_ctx ~temporal:sunday ~sanctoral:[ all_souls ] in Alcotest.(check (list string)) "All Souls is deferred (transferred), not omitted or commemorated" [ "ef-all-souls" ] @@ -1281,10 +1361,10 @@ let suite = Alcotest.test_case "All Souls transfers end-to-end (resolve, real rules)" `Quick test_all_souls_transfers_end_to_end ] @ List.map - (fun (desc, observed, comms, expect) -> + (fun (desc, observed, temporal, comms, expect) -> Alcotest.test_case desc `Quick (fun () -> Alcotest.(check (list string)) desc expect - (slugs_of (PE.admit ~observed comms)))) + (slugs_of (PE.admit ~observed ~temporal comms)))) admit_cases @ [ Alcotest.test_case "admit is order-independent (III-class, 3 candidates)" `Quick test_admit_order_independent; |
