The reader's zone, resolved into days and instants by the caller.
SPEC §7 makes a bucket a pure function of (due, lifecycle, priority, today, zone), and this store carries no timezone database - so a caller that wants buckets computes the edges and sends them, exactly as [TaskQuery::overdue] already does for the overdue split. Nothing here is guessed, defaulted or derived from a server clock: a store that decided what today meant would be wrong by morning and wrong in another country, which is the whole reason [ADR-287] refused to persist a bucket.
Six edges rather than the two a first sketch has, because the bucket function has two horizons and each of them has to be stated twice:
- a day edge, for dues stored as a calendar date or a floating wall clock - those carry a day that needs no zone to read; - an instant edge, for dues stored as a zoned instant, whose day is ZonedDateTime::date_in(zone) and therefore the caller's to compute.
The two are compared each in its own terms and never folded together ([ADR-183] rule 5). Calendar days here are inclusive last days - the day Next ends on, and the day Upcoming ends on - because that is how the domain function reads (within seven days, within thirty); the instants are the moments those days end, which is the same edge said the other way.
[ADR-183]: ../../../docs/decisions/ADR-201-225.md#adr-206-timemodel--koru-has-three-temporal-types-not-one-with-a-nullable-timezone [ADR-287]: ../../../docs/decisions/ADR-276-300.md#adr-287-taskread--the-tasks-query-is-a-second-question-asked-of-the-one-read-model
