diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-26 23:40:17 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-26 23:40:17 +0200 |
| commit | 2f6d25aff88b4c76c61e36889f1c017b3cc8faee (patch) | |
| tree | baf3027229ef3b95eff2d7fdf0b479f8bdbb2a87 /test/test_rite_of.ml | |
| parent | 1c0137dee8ff3858707281366662891a5ff01044 (diff) | |
| download | colitur-2f6d25aff88b4c76c61e36889f1c017b3cc8faee.tar.gz colitur-2f6d25aff88b4c76c61e36889f1c017b3cc8faee.zip | |
fix(of): anticipate St Joseph onto 18 March per Normae n. 56(f)
W1: when 19 March (St Joseph) falls on Palm Sunday, colitur sent him
forward to Easter+9 instead of anticipating the solemnity backward to
18 March, the one rule in the whole Normae transfer machinery that
names an earlier date. Live in 16 of 1583-2100 (1595, 1606, 1617,
1690, 1758, 1769, 1780, 1815, 1826, 1837, 1967, 1978, 1989, 2062,
2073, 2084).
Blocked on a kernel contract: Rite.t.transfer_target required its
result be strictly later than the impeded date, an obligation argued
purely from the EF's RG 96. Traced against Calendar's actual placement
pass rather than assumed unsafe: the round loop re-resolves the whole
year fresh every round, and its two safety nets (~start/~stop; the
round-count guard) both test the target's own value with no comparison
against origin, so a bounded backward jump converges the same way a
bounded forward one does. The one requirement that stays load-bearing
is target <> origin: Precedence.resolve never deduplicates by slug, so
a candidate returning its own argument unchanged would collide with
itself in the same round's contest. Relaxed the obligation accordingly
(rite.mli) and added the fourth transfer_target branch in
Precedence_of, ahead of the existing three (Precedence_of.transfer_target,
Rule 0). calendar.ml needed no logic change, only two comments that
asserted "every genuine transfer moves forward" as a blanket fact.
Unpinned the two tests that asserted the old wrong (forward) behaviour
and replaced them with assertions of the correct one, plus a new
direct unit test of the backward branch across two independent years.
EF output is untouched: data/ef/ and lib/rites/rite_ef/ carry no diff,
and colitur day/readings for 2026, 1583 and 9999 are byte-identical
against a build of the prior commit. OF's own 2005-2050 window carries
none of the 16 affected years and shows zero unexpected diffs; the
full 1583-9999 domain still reaches a fixed point under the exhaustive
sweep.
Diffstat (limited to 'test/test_rite_of.ml')
| -rw-r--r-- | test/test_rite_of.ml | 110 |
1 files changed, 57 insertions, 53 deletions
diff --git a/test/test_rite_of.ml b/test/test_rite_of.ml index 5e369b8..a7d3237 100644 --- a/test/test_rite_of.ml +++ b/test/test_rite_of.ml @@ -242,39 +242,35 @@ let test_transfers_reach_a_fixed_point_2005_2050 () = let slug_of (c : V.rank Cel.t) = Slug.to_string c.Cel.slug -(* precedence_of.mli's own documented, KNOWN-UNIMPLEMENTED fourth - transfer_target rule (final review Important #5, ledger ruling R9): - Normae n. 56(f) -- St Joseph's solemnity, falling on Palm Sunday, is - ANTICIPATED BACKWARD to 18 March, not carried forward. colitur's - [transfer_target] has no backward-search branch (rite.mli's own - [transfer_target] contract requires the result be strictly LATER than - the origin -- an EF-shaped kernel obligation, per that value's own - citation), so it instead sends Joseph forward via the general rule 3, - the same target date the Annunciation would already be heading to that - same year (Easter + 8). +(* RESOLVED ([of-normae-56f]/W1, 2026-08-26; previously the + precedence_of.mli-documented KNOWN-UNIMPLEMENTED fourth transfer_target + rule, final review Important #5, ledger ruling R9). Normae n. 56(f) -- + St Joseph's solemnity, falling on Palm Sunday, is ANTICIPATED BACKWARD + to 18 March, not carried forward. {!Colitur_kernel.Rite.t.transfer_target}'s + own obligation was relaxed from "strictly later than origin" to + "different from origin" (rite.mli's own comment carries the argument, + traced against {!Colitur_kernel.Calendar}'s actual placement pass, not + merely assumed safe), and [Precedence_of.transfer_target] gained a + Rule 0 for exactly this collision -- see that value's own .ml/.mli for + the full citation. - This is NOT fixed by this task (explicitly out of scope, per the task - brief) -- pinned here, on a REAL affected year, so the current - (known-wrong) behaviour is asserted deliberately rather than passing - silently as if it were correct. All years with Gregorian Easter = 26 - March put Palm Sunday on 19 March, coinciding with Joseph; 2062 is the - nearest one after today (2026) still inside the differential-adjacent - range this project favours for worked examples. + Previously pinned here as KNOWN WRONG (colitur sent Joseph forward to + Easter+9 via the general rule 3 instead); now pinned as CORRECT. All + years with Gregorian Easter = 26 March put Palm Sunday on 19 March, + coinciding with Joseph; 2062 is the nearest one after today (2026) + still inside the differential-adjacent range this project favours for + worked examples. 2062 is a doubly-worked example, not chosen only for Joseph: that same year, 25 March (the Annunciation) falls on HOLY SATURDAY (Easter - 1), - so BOTH solemnities are impeded and BOTH nominally target Easter + 8 via - the general rule -- {!Colitur_kernel.Calendar}'s own placement pass - settles that collision by landing whichever it processes first (Joseph, - departing the earlier date, 19 March) on Easter + 8 and pushing the - other to the next admissible day; empirically, on shipped data, it is - JOSEPH who is pushed one day further still, to Easter + 9 -- read as - further confirmation this is genuinely rule 3's general forward search - (sensitive to whatever else is competing that year), not the fixed, - collision-proof Easter+8 destination rule 3's cousin (the Annunciation's - own Holy-Week branch) names outright -- not as a claim about exactly - which of the two wins the tie, which this test does not depend on. *) -let test_joseph_palm_sunday_2062_known_wrong_forward_transfer () = + so the Annunciation is ALSO impeded and targets Easter + 8 via the + general rule -- independently of Joseph now, since Rule 0 is a fixed + one-day displacement that never enters the general search or competes + with the Annunciation's own target at all (Joseph departs 19 March for + 18 March; the Annunciation departs 25 March for Easter+8 -- the two no + longer collide the way they did when both were pushed toward the same + forward date). *) +let test_joseph_palm_sunday_2062_anticipated_backward () = let easter_2062 = Computus.gregorian_easter 2062 in Alcotest.(check string) "2062 Easter is really 26 March (the Normae n.56(f) trigger)" "2062-03-26" (Date.to_iso8601 easter_2062); @@ -285,36 +281,44 @@ let test_joseph_palm_sunday_2062_known_wrong_forward_transfer () = Alcotest.(check string) "25 March 2062 is really Holy Saturday, coinciding with the Annunciation too" "2062-03-25" (Date.to_iso8601 holy_saturday); let days = Cal.year real_of_rite real_of_layer 2061 in - let joseph_day = - Array.to_list days |> List.find (fun d -> Date.compare d.LD.date palm_sunday = 0) - in + let day_of d = Array.to_list days |> List.find (fun day -> Date.compare day.LD.date d = 0) in + let joseph_day = day_of palm_sunday in Alcotest.(check string) "Palm Sunday itself is observed on 19 March (Joseph impeded, correctly)" "of-palm-sunday" (slug_of joseph_day.LD.observed); let joseph_slug = "joseph-husband-of-the-blessed-virgin-mary" in let departure = List.find_opt (fun (c, _) -> slug_of c = joseph_slug) joseph_day.LD.transferred_out in - match departure with + let eighteen_march = Date.add_days palm_sunday (-1) in + (match departure with | None -> Alcotest.fail "expected Joseph to be transferred_out from 19 March 2062 (impeded by Palm Sunday)" | Some (_, target) -> - (* Concrete, not merely qualitative: 2062-04-04 is the actual pinned - value on shipped data today (Easter + 9, one day past the - Annunciation's own Easter + 8 -- see this test's own header). A - future data or Calendar change that moves it is meant to be - caught here; the point being pinned is the SHAPE (forward, past - Easter, not 18 March), asserted again below in a form that does - not depend on the exact day. *) Alcotest.(check string) - "KNOWN WRONG (Normae n.56(f) unimplemented, precedence_of.mli): Joseph lands forward, past \ - Easter (currently Easter+9, one day beyond the Annunciation's own Easter+8), not the \ - rubrically-correct 18 March (backward)" - "2062-04-04" (Date.to_iso8601 target); - Alcotest.(check bool) "not 18 March -- confirming this really is the anticipation defect, not a \ - coincidence" false - (Date.compare target (Date.add_days palm_sunday (-1)) = 0); - Alcotest.(check bool) "and it lands on or after Easter itself (rule 3's forward search, not a \ - backward anticipation)" true - (Date.compare target easter_2062 >= 0) + "Normae n.56(f): Joseph is anticipated BACKWARD to 18 March 2062, not carried forward" + "2062-03-18" (Date.to_iso8601 target); + Alcotest.(check bool) "which really is the day before Palm Sunday" true + (Date.compare target eighteen_march = 0)); + let march18_day = day_of eighteen_march in + Alcotest.(check string) "and 18 March 2062 itself observes St Joseph (not Cyril of Jerusalem's \ + ad-libitum memorial, not the ordinary Lenten Saturday feria)" + joseph_slug (slug_of march18_day.LD.observed); + let joseph_arrived = + match march18_day.LD.transferred_in with + | Some c -> slug_of c = joseph_slug + | None -> false + in + Alcotest.(check bool) "and 18 March 2062 records the arrival (transferred_in), not a silent placement" + true joseph_arrived; + (* {!Colitur_kernel.Rite.t.transfer_target}'s own second obligation + (terminate) reduces, for this liturgical year, to the whole-year + placement pass reaching a fixed point at all -- {!Val.run}'s own + "unconverged" check is exactly {!Colitur_kernel.Calendar}'s round + guard surfaced as a named failure (calendar.ml's own + [unconverged_reason]). *) + let failures = run 2061 in + Alcotest.(check bool) "the whole 2061 liturgical year still reaches a fixed point (no unconverged \ + transfer placement anywhere in it)" false + (List.exists (fun f -> f.Val.check = "unconverged") failures) (* Second NEWLY-FOUND defect, pinned the same way (see [is_known_holy_family_fallback_gap]'s own citation just above for the @@ -402,9 +406,9 @@ let suite = Alcotest.test_case "2005-2050: transfers reach a fixed point, nothing lost or duplicated" `Slow test_transfers_reach_a_fixed_point_2005_2050; Alcotest.test_case - "KNOWN OPEN DEFECT pinned, not fixed: St Joseph on Palm Sunday 2062 transfers forward, not \ - backward per Normae n.56(f)" `Quick - test_joseph_palm_sunday_2062_known_wrong_forward_transfer; + "RESOLVED (W1): St Joseph on Palm Sunday 2062 is anticipated backward to 18 March per Normae \ + n.56(f), converges, and is recorded as an arrival" `Quick + test_joseph_palm_sunday_2062_anticipated_backward; Alcotest.test_case "NEWLY-FOUND DEFECT pinned, not fixed: Holy Family's Normae n.35(a) 30-December fallback is \ unreached when Christmas Day is a Sunday (1583)" `Quick |
