# Recurrence stepping bounds

Status: revision 2 APPROVED by Claude Fable5.1 (claude-fable-5-1), 2026-09-07.
Evidence: /tmp/oficina-calendar-recurrence-review/design-review2.json.
Baseline: application branch 2074881; live binary d961b65. This support
branch does not approve the application's entire unmerged history.

Scope: bounded, exact stepping within the existing recurrence subset.
Keep every currently parsed positive INTERVAL; no parser or picker limit.
No UI copy, schema, migrations, COUNT fast-forwarding or new RRULE shapes.

## Evidence

Weekly INTERVAL=100000000 with BYDAY exceeds a two-second child deadline.
Civil 1600-01-01 to 2000-01-01 saturates at 106751 rather than146097 days.
A valid INTERVAL=20871 Saturday series silently loses its2000 occurrence
and reports complete. Yearly MaxInt wraps backwards. Invalid zone/start/end
reports complete, and a store-level test confirms strict busy-time reads
return nil rather than ErrIncompleteExpansion for those invalid fields.

## Revised implementation contract

1. Use civil(t).Unix()/86400 for integer civil days within the representable
   record domain: year0000 through9999, the four-digit local date format.
   All parsed source dates fit this domain. Generated candidates are bounded
   before arithmetic; no arbitrary-year Unix round-trip machinery is needed.
   daysBetween subtracts civil-day integers, never time.Duration or floats.
2. Weekly BYDAY considers remaining selected weekdays in the current eligible
   week, then the first selected weekday in the next INTERVAL-th week, ordered
   from WKST. cur is eligible by induction from DTSTART. At most13 weekday
   candidates; no scanning proportional to INTERVAL and no saturated phase.
   Construct each candidate with the original proto clock as before.
3. Check distance to the final representable civil date by division before
   multiplying. Daily compares interval with remaining civil days; weekly
   compares interval with remaining days/7 before computing its week jump.
   Monthly compares interval with remaining month indexes/step; yearly with
   remaining years/step. Thus every addition/product stays inside the small
   four-digit date domain. Do not change parsing or stored INTERVAL.
4. Test calendar-date existence before zone resolution. Yearly checks month
   length before constructing the candidate; monthly ordinal weekday arithmetic
   uses UTC civil weekdays, then resolves the selected date in loc. A complete
   flat4800-month-step or400-year-step search covers every Gregorian residue
   reachable by any integer interval, because those periods repeat the calendar.
   No match after that full search proves exhaustion. A horizon reached first
   does not prove exhaustion. No gcd machinery is required.
5. Stepping distinguishes candidate, proved exhaustion and incomplete. A
   horizon refusal is ALWAYS INCOMPLETE, regardless of query end: this avoids
   claiming a UTC cutoff for zones whose next local year starts before UTC's.
   Invalid Rule construction, non-advancing resolved candidates and resolved
   dates outside year0000..9999 also report incomplete. Ordinary DST clock
   normalization remains unchanged; intended-versus-resolved dates across a
   midnight gap remain a separate pre-existing issue, not silently redesigned.
6. Invalid zone/start/end or reversed event/window intervals make strict
   expansion incomplete. For an unreadable end preserve tolerant instantaneous
   output where possible, but retain an input-validity flag so no stop reason
   can turn it into complete. Existing canceled/note exceptions remain.
7. COUNT/UNTIL satisfaction, passing the window, a valid one-off or proved
   exhaustion are completion proofs. Check COUNT after generating its final
   candidate so no unneeded next step can turn completed COUNT into a horizon
   failure. Keep existing100000 outer/1000 output caps and EXDATE ordering.

## Validation

Adapt the two-second huge-interval probe to expect prompt incomplete refusal;
add INTERVAL=400000 within year9999 with exact date/weekday/clock. Keep the
four-century observable regression, reversed civil span, huge-interval cases
for every frequency, exact near-horizon boundaries, monthly31st/fifth weekday
and leap-day skips, WKST/DTSTART phase and existing DST/span tests.

Strict store regression must fail before the fix and pass after it while the
view remains tolerant. Test invalid input, COUNT completion near the horizon,
query beyond the horizon and unsupported direct Rule values. Mutation-prove
bounded stepping, exact day arithmetic and incomplete propagation. Run make ci,
then independent Fable branch review and actual CI before owner integration.
No production rollout of the unmerged application history is authorized here.

Revision1 was REQUEST CHANGES by Claude Fable5.1 (claude-fable-5-1), evidence
/tmp/oficina-calendar-recurrence-review/design-review.json. This revision
accepts the four-digit horizon, exact civil-day arithmetic, pre-zone cycle
proof and bounded weekly induction; explicitly chooses safe incomplete horizon
handling from the review's allowed alternatives.
