# Repeat work and calendar

30 October 2026. The bounded owner browser journey and stopped-data recovery are now recorded in [the v0.20.2 walkthrough](RECURRENCE-WORKFLOW-WALKTHROUGH.md). Phone and broader staff/customer checks remain open. The implementation guidance below began at v0.10; its older stage counts remain historical.

## Save a pattern, then review its visits

1. Create the customer/job and active named people in Jobs and Team. Open **Repeat work → New recurring definition**. Customer work must select the exact existing job; its original customer remains fixed. Unavailable time has no customer/job and can reserve named people or the whole team.
2. Enter a business-defined name, optional service label and private note. Choose a finite anchor/end date, pattern, people and duration. Saving creates only the definition. It does not create jobs, bookings, labour, documents or payments.
3. Choose **Generate a window**. The suggested window is 2/4/6/8/12 weeks, inclusive; nothing advances automatically. Preview shows every proposed or retained date, actual UK time, named people, skipped months and conflicts.
4. Review all rows, acknowledge any retained visits, and explicitly confirm. All ready changes commit together or none do. A stale preview or any conflict requires a fresh review. A repeat generation does not duplicate a saved visit, even with a different retry ID.
5. Calendar has Day, Week, Month and a Range of at most 62 dates, plus team/job/archive filters. Recurring cards link to their definition. Their ordinary edit/archive controls are guarded; use the reviewed recurrence actions.

A generation window supports up to 366 dates; rules support at most five years within 2020–2100. Each business is bounded to 100 retained definitions, 5,000 occurrences and 10,000 confirmed reviews. One preview supports at most 1,000 visits. These are local limits, not production capacity claims.

## Date and clock rules

- Weekly and fortnightly rules use selected weekdays and Monday-based weeks anchored to the chosen date. Dates before the anchor or after the end are never generated.
- Monthly, quarterly and yearly rules use the anchor month plus an explicit day of month. Choose **skip that month** or **use its last day** when the day does not exist. The original anchor remains stable, including leap years. Skipped months are shown without inventing an impossible date identity.
- Timed visits keep their London wall-clock start and duration of 1–1,440 minutes. They can cross midnight. The actual UTC duration can differ when clocks change. All-day visits span 1–7 inclusive dates; UK days can be 23 or 25 hours.
- Missing spring-clock times either stop the preview or produce an explicit skipped/excluded visit, according to the saved policy. Repeated autumn times require explicit first/second choices for affected endpoints. Times are never silently shifted. Preview displays the resulting UK clock labels.
- A visit whose end would pass the supported year boundary is rejected. Date blocks include nominal and actual covered dates; an end at exactly midnight does not occupy the following day.

## Single visits, holidays and saved identity

Each visit has an immutable contract + original date identity, an immutable occurrence ID and, once created, one stable booking ID. Rescheduling changes its actual dates, not that identity. A cancellation is retained explicitly and never recreated by regeneration.

Use **Review reschedule**, **Review cancellation**, **Apply active date block** or **Review restoration** beside a saved visit. Add a reason, preview and confirm. Restoring a saved visit rechecks people, conflicts and all currently active date blocks. Its original job/customer cannot change. A saved override remains an override even if the series later changes.

A holiday/date block is inclusive and reversible. Overlapping blocks are independent: removing one does not remove another. A removed block does not undo a deliberate cancellation or rewrite a manual override. The preview identifies overrides and protected visits needing individual review. Applying a block to one of those visits requires its own **Apply active date block** review; that exclusion is distinct from a permanent cancellation.

## Work history and future changes

Past nominal or actual visit dates are read-only. Existing v0.9 field logs, timer intervals, time, photos, notes, materials and document sources are linked to the **job**, not to a specific recurring occurrence. This release does not guess those missing links or relabel old work as belonging to a visit.

Bulk pattern/holiday changes therefore retain existing visits when the shared job carries work/history or a progressed/closed stage. The preview lists them and requires acknowledgement; it never silently claims those visits were changed. This is a bulk-review limit, not a permanent lock on future work.

For a clearly future visit, an owner can explicitly review it as **unstarted**, acknowledge that all existing job history remains, supply a reason and separately cancel, reschedule, exclude or restore it. Tests cover an ongoing job with converted two-person work, photos, a field log and an issued source-linked invoice; a future change preserves every work/document row and the stable visit/booking IDs. Past visits remain protected. A visit today with shared job history remains review-blocked because the legacy links cannot establish which visit progressed. Moving an acknowledged future visit onto that ambiguous current date is also blocked. Exact work-to-occurrence linking is a later enhancement.

Completed, cancelled and on-hold jobs cannot receive newly scheduled work until their job stage is deliberately reviewed. Cancelling unwanted future bookings does not change job stage or work records.

## Future series and state changes

**Change future pattern** appends an immutable rule revision from the chosen date. It supersedes older future definitions from that date, including future rules saved earlier. The preview reconciles every already-generated later occurrence, even beyond the selected window; new dates are generated only inside the reviewed window. Removed pattern dates become retained exclusions. Past work, manual overrides and job-history holds remain visible.

Pause and retire stop future generation and retain existing bookings, matching the useful source behaviour. Restore a retired definition as paused, then resume separately. Neither action creates visits. Existing eligible bookings can be deliberately revised while paused; excluded/new visits do not resume automatically. Every confirmed review and full proposal/result remains readable in history.

## Staff and customer boundaries

All seven recurring-definition/review routes are owner-only under default-deny policies. Business databases and exact object/customer/job checks prevent cross-business access. Staff receive only assigned booking information plus recurring/original-date/override flags, not private rules, contract notes, costs or owner history. Customers have no recurrence-management access.

Removing a person's final active assignment interrupts a staff-authored running timer at its last confirmed server timestamp and releases locks. Revoked staff access also applies to old retry IDs. Owners review/convert interrupted captures explicitly. Other active bookings for the same person/job retain assignment, including historical bookings that remain unarchived under the existing assignment model. Owner-authored captures are not ended by this scheduling action. Booking changes never create or alter labour or invoices.

## Recovery and evidence

Format 7 adds definitions, immutable rules, exclusion blocks, stable occurrences, complete history and saved review plans/results. Exact schemas for formats 1–6 are pinned. Validation checks original relationships, versions/history chains, rule snapshots, cross-contract links, generated calendar states/history and membership authors. A populated format-6 upgrade is tested.

The four-business source-loss drill preserves 4 definitions, 8 rules, 24 occurrences, 4 past visits, 4 manual overrides, 4 cancellations, 8 excluded visits and 8 overlapping blocks, plus field/photo/labour/issued-document data. It deletes only its disposable fictional source before restoring. Old credentials/sessions/portal grants fail. Four open captures restore as interrupted at the last confirmation; no visits, labour, bills or payments are generated. A second backup verifies. See recurrence-recovery-drill.json and BACKUP-AND-RECOVERY.md.

Current evidence: 370 backend tests (320 prior + 37 recurrence + 13 recurrence recovery), 41 JavaScript tests, 24 server-render smoke cases, frontend build, 152 explicit route policies and 10 no-browser loopback route checks. The normal demo's prior rows remain unchanged and operational tables empty. Setup remains unacknowledged. These checks are not browser, device, deployment or production evidence.

## Source comparison and remaining gaps

Source-only review: routers/calendar.py:198–449, models.py:337–390, CalendarSection.jsx and DashboardDialogs.jsx:2100–2315. These establish weekly contracts, named admins, windows, generation/conflicts, pause/delete retaining bookings and inclusive cancellation blocks. New-job dialogs declare weekly/monthly/quarterly/yearly recurrence; no working monthly/quarterly/yearly generator was found in the supplied export. Fortnightly and their explicit calendar arithmetic are documented local extensions.

The independent implementation replaces partial batch creation and date/start-based duplicate detection with atomic review and stable original-date identities. It applies active holiday exclusions during generation and preserves cancellation/override history. No source runtime, integration task, customer-specific name/rate scheme or real record is imported.

Still pending: interactive owner/staff/customer/browser/phone verification, drag/drop, calendar print/share, external calendar sync/notifications, specialist configurable contract rates and batch billing, occurrence-linked field capture, calendar exports, PWA/offline replay and wider parity. The original 14 SHS findings remain open. Next bounded candidate: source-backed customer portal completion and private document/PDF export, preserving customer isolation and original document snapshots. Any external delivery or deployment remains separate.
