summaryrefslogtreecommitdiff
path: root/lib/kernel/calendar.mli
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 20:01:31 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 20:01:54 +0200
commit8de560db7fb1b7b7d3ca93285068c6a4214e0bff (patch)
tree3f19ec479846ec858dcb09ac85526a0d3e77dace /lib/kernel/calendar.mli
parent6436509d6b599b7d7c6467bd39c8090cb9634889 (diff)
downloadcolitur-8de560db7fb1b7b7d3ca93285068c6a4214e0bff.tar.gz
colitur-8de560db7fb1b7b7d3ca93285068c6a4214e0bff.zip
kernel(calendar): the year is the primitive, the day is derived
Transfers make per-date resolution impossible to do correctly: resolving 25 March can push a feast onto 26 March, and RG 97-98 has coinciding I-class feasts transfer in table order, which needs global knowledge. So year computes a whole liturgical year in one pass and day indexes into it. Pure, no cache, no mutable state. This commit resolves each day but does not yet place deferred transfers; they are recorded with a reason. Task 6 adds the placement pass.
Diffstat (limited to 'lib/kernel/calendar.mli')
-rw-r--r--lib/kernel/calendar.mli45
1 files changed, 45 insertions, 0 deletions
diff --git a/lib/kernel/calendar.mli b/lib/kernel/calendar.mli
new file mode 100644
index 0000000..50ff8f8
--- /dev/null
+++ b/lib/kernel/calendar.mli
@@ -0,0 +1,45 @@
+(** Resolution across a whole liturgical year (spec ยง2.4).
+
+ Transfers make per-date resolution impossible to do correctly: resolving
+ 25 March can push a feast onto 26 March, and RG 97-98 has coinciding
+ I-class feasts transfer in table order, which needs global knowledge of
+ the whole year. So [year] is the primitive -- it resolves every date in
+ one pass -- and [day] is derived: it finds the liturgical year containing
+ a date and indexes into it. Both are pure; neither caches.
+
+ This module resolves each day's temporal-vs-sanctoral contest but does
+ not yet place deferred transfers (RG 96-98): a losing candidate the
+ rite's rules send to [Precedence.Transfer] is absent from the result
+ entirely on this pass -- not observed, not commemorated, and
+ [transferred_in]/[transferred_out] both stay [None] everywhere. Task 6
+ adds the fixed-point placement pass that closes this gap. *)
+
+(** [year rite layer y] resolves every day of the liturgical year that opens
+ in civil year [y]: from [rite.year_start y] through the day before
+ [rite.year_start (y + 1)], inclusive of both ends.
+
+ Total over 1583..9999, including the boundary years:
+ - At [y] = 9999, [rite.year_start (y + 1)] would ask for civil year
+ 10000, out of {!Date}'s domain (this is the bug Plan 2 shipped in
+ [Validate] and later fixed). The end of the walk clamps to 31 December
+ 9999 instead of computing that call; the returned year comes back
+ truncated to whatever the rite's own temporal cycle covers between
+ [rite.year_start 9999] and the last day of that civil year, not
+ un-computable.
+ - Symmetrically, [y] < 1583 clamps the start of the walk to 1 January
+ 1583 instead of calling [rite.year_start y] on an out-of-domain civil
+ year. [year] is never called this way directly by anything in this
+ module; {!day} is the only caller that can reach [y] = 1582 (one below
+ the floor, never lower), when the date it was asked about sits in civil
+ year 1583 before that year's own [rite.year_start] -- i.e. the sliver
+ whose true liturgical year opened in civil year 1582, which the domain
+ cannot represent. Calling [year] with such a [y] directly is also safe:
+ it returns exactly that truncated sliver. *)
+val year : ('s, 'r) Rite.t -> 'r Layer.t -> int -> ('s, 'r) Liturgical_day.t array
+
+(** [day rite layer date] finds the liturgical year containing [date] -- the
+ year [y] with [rite.year_start y <= date < rite.year_start (y + 1)] --
+ and returns its slot for [date]. Recomputes that whole year on every
+ call: pure, no cache, no mutable state. Acceptable cost for the natural
+ usage (dump a year, sweep years for validation), which pays it once. *)
+val day : ('s, 'r) Rite.t -> 'r Layer.t -> Date.t -> ('s, 'r) Liturgical_day.t