AllDayRecurrence

AllDayRecurrence(id) :: # (opaque)

Stream identified all-day occurrences in source-date order. The window selects source dates, not timeline overlaps. Duration may extend beyond it. IDs pair the supplied series identity with each original Gregorian date.

new : id, DateRecurrence, Window, U64, ZoneRules -> Try(AllDayRecurrence(id), [InvalidDuration, EmptyWindow, ReversedWindow, ..])
collect : AllDayRecurrence(id), { work : Limits, max_occurrences : U64 } -> Try(Batch(id), [OutOfRange, OutsideValidity, ..])

Materialize at most max_occurrences. Work budgets apply to the whole call, not separately to each emitted occurrence. Reaching output capacity returns Limited without looking ahead to prove End. Resume its cursor.

next : AllDayRecurrence(id), Limits -> Try(Next(id), [OutOfRange, OutsideValidity, ..])

At most one date-cursor advance and one bounded zone-cursor advance. A pending occurrence resumes before any new date is consumed. Empty coverage still emits an occurrence; skipped civil days do not erase IDs.

outcomes : AllDayRecurrence(id), Limits -> Iter(Try(Next(id), [OutOfRange, OutsideValidity]))

Every advancement exposes its outcome. End, errors and Limited are terminal items; resume a Limited cursor explicitly with chosen budgets.

Limits : { max_date_steps : U64, max_date_buffered : U64, max_zone_segments : U64, max_zone_members : U64 }
Limit : [DateWorkLimit, DateBufferLimit, ZoneWorkLimit, ZoneBufferLimit, OutputLimit]
Batch : {
    occurrences : List(AllDayOccurrence({ series : id, date : GregorianDate })),
    date_steps : U64,
    zone_segments : U64,
    status : [Complete, Limited({ cursor : AllDayRecurrence(id), reason : Limit })],
}
Next : {
    date_steps : U64,
    date_buffered : U64,
    zone_segments : U64,
    zone_buffered : U64,
    status : [End, Item({ occurrence : AllDayOccurrence({ series : id, date : GregorianDate }), cursor : AllDayRecurrence(id) }), Limited({ cursor : AllDayRecurrence(id), reason : Limit })],
}