| 1 | # Recurrence stepping bounds |
| 2 | |
| 3 | Status: revision 2 APPROVED by Claude Fable5.1 (claude-fable-5-1), 2026-09-07. |
| 4 | Evidence: /tmp/oficina-calendar-recurrence-review/design-review2.json. |
| 5 | Baseline: application branch 2074881; live binary d961b65. This support |
| 6 | branch does not approve the application's entire unmerged history. |
| 7 | |
| 8 | Scope: bounded, exact stepping within the existing recurrence subset. |
| 9 | Keep every currently parsed positive INTERVAL; no parser or picker limit. |
| 10 | No UI copy, schema, migrations, COUNT fast-forwarding or new RRULE shapes. |
| 11 | |
| 12 | ## Evidence |
| 13 | |
| 14 | Weekly INTERVAL=100000000 with BYDAY exceeds a two-second child deadline. |
| 15 | Civil 1600-01-01 to 2000-01-01 saturates at 106751 rather than146097 days. |
| 16 | A valid INTERVAL=20871 Saturday series silently loses its2000 occurrence |
| 17 | and reports complete. Yearly MaxInt wraps backwards. Invalid zone/start/end |
| 18 | reports complete, and a store-level test confirms strict busy-time reads |
| 19 | return nil rather than ErrIncompleteExpansion for those invalid fields. |
| 20 | |
| 21 | ## Revised implementation contract |
| 22 | |
| 23 | 1. Use civil(t).Unix()/86400 for integer civil days within the representable |
| 24 | record domain: year0000 through9999, the four-digit local date format. |
| 25 | All parsed source dates fit this domain. Generated candidates are bounded |
| 26 | before arithmetic; no arbitrary-year Unix round-trip machinery is needed. |
| 27 | daysBetween subtracts civil-day integers, never time.Duration or floats. |
| 28 | 2. Weekly BYDAY considers remaining selected weekdays in the current eligible |
| 29 | week, then the first selected weekday in the next INTERVAL-th week, ordered |
| 30 | from WKST. cur is eligible by induction from DTSTART. At most13 weekday |
| 31 | candidates; no scanning proportional to INTERVAL and no saturated phase. |
| 32 | Construct each candidate with the original proto clock as before. |
| 33 | 3. Check distance to the final representable civil date by division before |
| 34 | multiplying. Daily compares interval with remaining civil days; weekly |
| 35 | compares interval with remaining days/7 before computing its week jump. |
| 36 | Monthly compares interval with remaining month indexes/step; yearly with |
| 37 | remaining years/step. Thus every addition/product stays inside the small |
| 38 | four-digit date domain. Do not change parsing or stored INTERVAL. |
| 39 | 4. Test calendar-date existence before zone resolution. Yearly checks month |
| 40 | length before constructing the candidate; monthly ordinal weekday arithmetic |
| 41 | uses UTC civil weekdays, then resolves the selected date in loc. A complete |
| 42 | flat4800-month-step or400-year-step search covers every Gregorian residue |
| 43 | reachable by any integer interval, because those periods repeat the calendar. |
| 44 | No match after that full search proves exhaustion. A horizon reached first |
| 45 | does not prove exhaustion. No gcd machinery is required. |
| 46 | 5. Stepping distinguishes candidate, proved exhaustion and incomplete. A |
| 47 | horizon refusal is ALWAYS INCOMPLETE, regardless of query end: this avoids |
| 48 | claiming a UTC cutoff for zones whose next local year starts before UTC's. |
| 49 | Invalid Rule construction, non-advancing resolved candidates and resolved |
| 50 | dates outside year0000..9999 also report incomplete. Ordinary DST clock |
| 51 | normalization remains unchanged; intended-versus-resolved dates across a |
| 52 | midnight gap remain a separate pre-existing issue, not silently redesigned. |
| 53 | 6. Invalid zone/start/end or reversed event/window intervals make strict |
| 54 | expansion incomplete. For an unreadable end preserve tolerant instantaneous |
| 55 | output where possible, but retain an input-validity flag so no stop reason |
| 56 | can turn it into complete. Existing canceled/note exceptions remain. |
| 57 | 7. COUNT/UNTIL satisfaction, passing the window, a valid one-off or proved |
| 58 | exhaustion are completion proofs. Check COUNT after generating its final |
| 59 | candidate so no unneeded next step can turn completed COUNT into a horizon |
| 60 | failure. Keep existing100000 outer/1000 output caps and EXDATE ordering. |
| 61 | |
| 62 | ## Validation |
| 63 | |
| 64 | Adapt the two-second huge-interval probe to expect prompt incomplete refusal; |
| 65 | add INTERVAL=400000 within year9999 with exact date/weekday/clock. Keep the |
| 66 | four-century observable regression, reversed civil span, huge-interval cases |
| 67 | for every frequency, exact near-horizon boundaries, monthly31st/fifth weekday |
| 68 | and leap-day skips, WKST/DTSTART phase and existing DST/span tests. |
| 69 | |
| 70 | Strict store regression must fail before the fix and pass after it while the |
| 71 | view remains tolerant. Test invalid input, COUNT completion near the horizon, |
| 72 | query beyond the horizon and unsupported direct Rule values. Mutation-prove |
| 73 | bounded stepping, exact day arithmetic and incomplete propagation. Run make ci, |
| 74 | then independent Fable branch review and actual CI before owner integration. |
| 75 | No production rollout of the unmerged application history is authorized here. |
| 76 | |
| 77 | Revision1 was REQUEST CHANGES by Claude Fable5.1 (claude-fable-5-1), evidence |
| 78 | /tmp/oficina-calendar-recurrence-review/design-review.json. This revision |
| 79 | accepts the four-digit horizon, exact civil-day arithmetic, pre-zone cycle |
| 80 | proof and bounded weekly induction; explicitly chooses safe incomplete horizon |
| 81 | handling from the review's allowed alternatives. |
| 82 | |