ADR-0032: Editing a repeating event's rule
Metadata
- Status: Accepted
- Date: 2026-08-16
- Deciders: Eagraí Clainne Team
- Related: ADR-0009 (service layer authorization), issue #77, issue #94 (EVENT_MOVED)
Context
An event's recurrence was fixed at creation. UpdateEventRequest carried
no repeat field, and both edit forms deliberately hid the repeat control:
a rule change is not a plain field update. It re-derives every future
occurrence, and it collides with the one-off edits a series accumulates —
split children (a moved or reworded occurrence) and tombstones (a
cancelled slot), both stored as child rows keyed by the slot date they
replace.
Meanwhile the common ask is small: end a series earlier, push its until
out, or change Tuesday swimming to Thursday. Members had to delete the
series and rebuild it, losing its history and its one-off edits.
Decision
The rule is editable for the whole series, through EventService/Update.
UpdateEventRequestgains arepeatfield (presence = replace the rule, validated like a created rule) and aclear_repeatflag (the series stops repeating; the parent stays as a plain event). No new RPC: the membership guard, the audit trail and the EVENT_MOVED emission areUpdate's already, and aPermissionMatrixentry forUpdateexists.- The new rule applies from the series start. The series re-derives
from its own anchor under the new rule. "Change from here forward"
(split the series at today) is deliberately deferred — the split
machinery exists (
SplitOccurrence), but the two-rule series it implies is a bigger shape than the common ask needs. - Child rows survive where their slot survives. A split child or a
tombstone whose
occurrence_datestill lands on a projected slot under the new rule is kept — the one-off edit or cancellation still means something. A child whose slot no longer exists is deleted in the same transaction as the rule write: it refers to an occurrence that no longer happens, and keeping it would strand an orphan on the calendar (stray children are deliberately still rendered — that mechanism is for slots outside the window, not slots outside the rule). - A rule change is a move. The members hear EVENT_MOVED (issue #94), because the rule decides where occurrences land exactly as the start time does.
Consequences
- The common cases — extend or cut
until, change the weekday set, widen the interval — are one edit on the series, keeping history, membership and surviving one-off edits. - Orphaned child deletions ride the parent's UPDATE mutation and audit entry rather than minting per-child DELETE entries: the user performed one action, the audit log records one action.
- A rule change under a projected occurrence a member is looking at can make that occurrence vanish; the EVENT_MOVED notification is the compensating signal.
- The deferred "from here forward" flow can compose later: split the series at a date, then edit the tail's rule with this mechanism.
Alternatives considered
- A dedicated
SetRepeatRPC — a cleaner wire shape, but it would duplicateUpdate's guard, audit and notification wiring for one field, and need its own matrix entry for the same audience. - Discard all child rows on any rule change — simplest to implement
and explain, but it silently throws away one-off edits that still make
sense under the new rule (cutting
untilshorter would wipe every past override). - Apply the new rule from "here forward" only — the semantically richest option, deferred as above.