diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-12 01:16:22 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-12 01:16:22 +0200 |
| commit | 94fc488cc9c6b4a050d90c4250f6e166b40088e7 (patch) | |
| tree | 18f68c393a704c225c0124f6c9a30bdd96e444ae /test/test_precedence_ef.ml | |
| parent | 9725195fc4a1050ded151854f6653459dacc35b0 (diff) | |
| download | colitur-94fc488cc9c6b4a050d90c4250f6e166b40088e7.tar.gz colitur-94fc488cc9c6b4a050d90c4250f6e166b40088e7.zip | |
rite(ef): clamp the RG96 search at the domain ceiling
search_from could walk up to 400 days past origin before Calendar's own
~start ~stop clamp is ever consulted, and nothing stopped it probing
occupant on a date past 31 December 9999 -- occupant chains through the
real EF rite's temporal, which calls Computus.gregorian_easter, not
total outside 1583..9999 (it Date.makes and failwiths on Error).
Not reachable with the shipped sanctoral data alone, but reachable
through the project's own primary extension path: an overlay adding an
I-class feast on 25 December leaves nothing but Class2 Nativity-octave
days for the rest of civil year 9999, so the unguarded search reached 1
January of year 10000 and crashed there with 'computus: year 10000 out
of range 1583..9999'. 9999 is an in-range year and the kernel's contract
is 'never raises on in-range input'.
search_from now also stops, without probing occupant again, once it
passes Date's own domain ceiling -- the same 'return a finite date, let
Calendar's own out-of-range handling record it, never pretend to have
found something admissible' contract the existing step-count guard
already follows.
Two new tests, both mutation-verified to actually reproduce the crash
when the guard is removed (see the task report): a precedence_ef.ml unit
test using the real Temporal_ef.temporal as occupant (a synthetic
occupant can never discriminate this, since it never calls Computus
itself), and a Calendar-level integration test reproducing the exact
overlay-based scenario the review found.
Diffstat (limited to 'test/test_precedence_ef.ml')
| -rw-r--r-- | test/test_precedence_ef.ml | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/test/test_precedence_ef.ml b/test/test_precedence_ef.ml index 084d708..0973a93 100644 --- a/test/test_precedence_ef.ml +++ b/test/test_precedence_ef.ml @@ -897,6 +897,34 @@ let test_transfer_target_terminates_under_pathological_occupant () = true (D.compare target (D.add_days origin 1000) <= 0) +(* Coordinator review: [search_from] must not probe [occupant] past + {!Date}'s own domain ceiling (31 December 9999). A SYNTHETIC occupant + (like [occupant_always_blocking] above) can never actually discriminate + this: it never calls [Computus.gregorian_easter] itself, so it cannot + raise regardless of whether the domain guard exists -- a test built on + one would only prove [search_from]'s unrelated step bound, not this fix. + [occupant] here is instead the REAL [Temporal_ef.temporal] (no sanctoral + layer needed: 29-31 Dec are ALREADY II class via [named]'s own Nativity- + octave-day entries, so three real, unbroken blocking days already sit at + the very end of the domain) -- exactly the shape that raises without the + fix: 1 January of civil year 10000 is next, and [Computus.gregorian_easter + 10000] does [Date.make ~year:10000 ...] and [failwith]s (the .ml's own + [domain_max_date] comment; also how the reviewer reproduced the bug + through the project's own overlay mechanism -- see the task report for + that end-to-end reproduction). Mutation-verified: reverting the domain + guard makes this test error with exactly that uncaught [Failure], not + merely fail an assertion (see the task report). *) +let test_transfer_target_does_not_raise_at_domain_ceiling () = + let origin = mk 9999 12 28 in + let occupant d = (T.temporal d).Colitur_kernel.Temporal.office in + let c = cand ~origin:P.Sanctoral ~layer:PE.universal_layer "ef-domain-ceiling-case" in + let target = PE.transfer_target c origin occupant in + Alcotest.(check bool) "past 31 December 9999 (the guard engaged; nothing admissible remained \ + in-domain, so the search gave up at the ceiling rather than crashing)" + true + (D.compare target (mk 9999 12 31) > 0) + + let suite = ( "Precedence_ef", List.map @@ -947,4 +975,6 @@ let suite = "transfer_target: Annunciation exception searches onward if that Monday is blocked" `Quick test_transfer_target_annunciation_searches_onward_if_blocked; Alcotest.test_case "transfer_target: terminates and stays forward under a pathological occupant" - `Quick test_transfer_target_terminates_under_pathological_occupant ] ) + `Quick test_transfer_target_terminates_under_pathological_occupant; + Alcotest.test_case "transfer_target: does not raise probing past the domain ceiling" `Quick + test_transfer_target_does_not_raise_at_domain_ceiling ] ) |
