feat: support safe recurrence additions

Parse, persist, expand, and round-trip compatible RDATE values while preserving whole-series TUI behavior and conservative rewrite guards.

Verified: normal, warning-as-error, and ASan/UBSan builds pass all 9 suites; storage failure paths preserve calendar and backup bytes; live PTY restores terminal state.
This commit is contained in:
2026-07-18 10:14:53 +01:00
parent 989332ef9a
commit cfca6ab6d0
16 changed files with 498 additions and 69 deletions

View File

@@ -36,8 +36,11 @@ requested time window and return values that point back to their source series,
preserving series-level storage and mutation semantics. The supported rule
surface is deliberately bounded to daily/weekly/monthly/yearly frequency,
interval, count or until, weekly `BYDAY`, monthly `BYMONTHDAY`, yearly
`BYMONTH`, and `EXDATE`. Invalid metadata retains at most the base event rather
than crashing a render.
`BYMONTH`, compatible DATE or DATE-TIME `RDATE`, and `EXDATE`. An occurrence set
merges `DTSTART`, rule expansion, and additional `RDATE` starts, deduplicates by
start, and then subtracts exclusions. Mutations continue to address the source
series as a whole. Invalid metadata retains at most the base event rather than
crashing a render.
Search matching is a pure domain predicate over normalized event text; the TUI
owns result presentation and occurrence identity. Recurring searches expand a
@@ -107,12 +110,13 @@ combined with any of the other modes.
The current writer deliberately refuses to mutate an existing file when the
loader encounters information it cannot round-trip, including recurrence
overrides, `RDATE`, custom `VTIMEZONE` definitions, alarms, attendees, unknown
properties, or malformed components. Supported recurrence rules, exclusions,
and system IANA time-zone identifiers round-trip semantically. Browsing remains
available for unsupported files. This conservative boundary is more important
than partial editing because a successful-looking edit must not erase unrelated
calendar data.
overrides, `RDATE` periods or values incompatible with `DTSTART`'s time basis or
`TZID`, custom `VTIMEZONE` definitions, alarms, attendees, unknown properties,
or malformed components. Supported recurrence rules, compatible additional
starts, exclusions, and system IANA time-zone identifiers round-trip
semantically. Browsing remains available for unsupported files. This
conservative boundary is more important than partial editing because a
successful-looking edit must not erase unrelated calendar data.
Provider synchronization will not write directly into this UI file. It will use
a transaction-capable local cache and preserve remote ETags/sync tokens in a

View File

@@ -89,22 +89,28 @@ read-only instead of being discarded. Saves reject external changes, retain a
last-known-good backup, and feed bounded session undo/redo history. Supported
recurring instances appear throughout the month, preserve civil time across
daylight-saving changes, and expose their source zone and whole-series mutation
semantics in the reader. `/` searches occurrence-aware title, description,
location, and calendar-ID matches in a finite ten-year window centered on the
selected date. `c` toggles session-only calendar visibility consistently across
the grid, appointment focus, and search without filtering the model supplied to
persistence. `g` opens an occurrence-aware agenda at the selected month date;
navigation is bounded to consecutive 42-day windows and `Enter` returns to the
exact occurrence in the month grid. `Esc` or `g` closes the agenda without
changing the month selection unless an occurrence was chosen. Hidden calendars
remain filtered there, while calendar selection and search can overlay the
agenda. Agenda navigation never persists state, and add/edit/delete remain in
the month workflow. Week-start selection rotates only the month grid, header,
and the visible range used by its month queries; storage, agenda windows, and
semantics in the reader. A supported recurrence set combines `DTSTART`, rule
expansion, and compatible DATE or DATE-TIME `RDATE` starts, deduplicates starts,
and then removes `EXDATE` exclusions. `/` searches occurrence-aware title,
description, location, and calendar-ID matches in a finite ten-year window
centered on the selected date. `c` toggles session-only calendar visibility
consistently across the grid, appointment focus, and search without filtering
the model supplied to persistence. `g` opens an occurrence-aware agenda at the
selected month date; navigation is bounded to consecutive 42-day windows and
`Enter` returns to the exact occurrence in the month grid. `Esc` or `g` closes
the agenda without changing the month selection unless an occurrence was
chosen. Hidden calendars remain filtered there, while calendar selection and
search can overlay the agenda. Agenda navigation never persists state, and
add/edit/delete remain in the month workflow. Week-start selection rotates only
the month grid, header, and the visible range used by its month queries;
storage, agenda windows, and
recurrence rules are unchanged. The default remains Monday for backward
compatibility. The CLI accepts the exact lowercase values `monday`, `tuesday`,
`wednesday`, `thursday`, `friday`, `saturday`, and `sunday`. The next local-data
work adds advanced recurrence overrides and rule editing.
`wednesday`, `thursday`, `friday`, `saturday`, and `sunday`. `RDATE` periods,
values incompatible with the event's `DTSTART` time basis or `TZID`, detached
`RECURRENCE-ID` overrides, and embedded `VTIMEZONE` definitions remain
read-only. Remaining local-data work includes detached overrides and rule
editing.
## Local file interchange

View File

@@ -8,7 +8,8 @@
- Validated add/edit/delete forms with confirmation and failure rollback
- Guarded atomic `.ics` persistence, advisory locking, and round-trip tests
- Bounded session undo/redo, exact external-change detection, and backup recovery
- Windowed recurrence expansion, EXDATE, IANA TZID, and multi-day segment cues
- Windowed recurrence expansion, compatible RDATE, EXDATE, IANA TZID, and
multi-day segment cues
- Occurrence-aware appointment search with exact result-to-grid navigation
- Session calendar toggles shared by month rendering, focus, and search
- Read-only 42-day agenda with bounded recurrence and exact return navigation
@@ -19,7 +20,8 @@
## 0.1 — complete local calendar
- Advanced recurrence editing, RDATE/overrides, and embedded VTIMEZONE support
- Advanced recurrence rule editing and detached RECURRENCE-ID overrides
- Embedded VTIMEZONE support
- Screen-reader-friendly linear view and full Unicode display-width handling
## 0.2 — durable cache and provider boundary