7d23c8b3

ical-recurrence: handle RECURRENCE-ID

An overriding component appears as an **extra** occurrence beside the instance it is supposed to replace. Google and Outlook emit a `RECURRENCE-ID` for every "this event only" edit, so this fires on ordinary calendars: the edited instance shows up twice, once where it used to be and once where it now is.

Two commits: the first is red, the second is the fix.

## Why it is wrong

[§3.8.4.4](https://datatracker.ietf.org/doc/html/rfc5545#section-3.8.4.4):

> This property is used in conjunction with the "UID" and "SEQUENCE" properties to identify a specific instance of a recurring "VEVENT", "VTODO", or "VJOURNAL" calendar component. The property value is the original value of the "DTSTART" property of the recurrence instance.

> The DATE-TIME value is set to the time when the original recurrence instance would occur; meaning that if the intent is to change a Friday meeting to Thursday, the DATE-TIME is still set to the original Friday meeting.

The `RECURRENCE-ID` says where the instance used to be and the overriding component's own `DTSTART` says where it is now. Both cannot be in the recurrence set: the meeting moved, it did not happen twice.

## Matching

Exact comparison of the property value against the generated instance's start, which is what the same section makes possible:

> This property MUST have the same value type as the "DTSTART" property contained within the recurring component. Furthermore, this property MUST be specified as a date with local time if and only if the "DTSTART" property contained within the recurring component is specified as a date with local time.

So a `RECURRENCE-ID` that matches none of them exactly is non-conforming input rather than a near miss to be resolved. `RANGE=THISANDFUTURE` is **not** handled here; it is the only part with real arithmetic and gets its own PR.

## The cases the spec does not define

Three new fixable errors, each keeping what the calendar said rather than dropping it:

| Error | Case | What it does |
| --- | --- | --- |
| `RecurrenceIdentifierUnmatched` | An override naming no instance the series generates | The override contributes its own instance |
| `RecurrenceIdentifierDuplicate` | Two overrides of one instance at the same `SEQUENCE` | `Ord` picks the winner |
| `RecurrenceMultipleSeries` | Two components of one UID with no `RECURRENCE-ID` between them | Both are expanded |

A higher `SEQUENCE` wins outright — §3.8.7.4 says it "is monotonically incremented [...] each time the 'Organizer' makes a significant revision", so the higher one is the later revision. A tie contradicts that and the calendar does not say which to take, so `Ord` settles it rather than the order the components happen to appear in the file, following the colliding-observances precedent from #30.

## Tests

A fixable error must halt a conforming run and succeed leniently, and these are the errors that only a *group* of components can have, so they need a whole calendar rather than the single component `test_resources/event/fixable` holds. Hence `test_resources/calendar/fixable`, with the same two tests per file. `scenarioDir` does not recur into subdirectories, so `test_resources/calendar` does not also pick them up.

Each of those four goldens was derived by hand rather than generated, and each fixture's overriding component starts at a different time from the instance it replaces, so the golden shows which component won without the format having to name it. Unit tests pin *which* fixable error was emitted, which the scenario directory cannot say.

**Every pre-existing `.occ` and `.res` golden is still byte-identical.**

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 0s 1s 1s 1s 0s
Eval 1s 10s 10s 12s 0s
Build 11s 1m03s 1m03s 1m15s 0s
Suite 0s 1m15s 1m14s 1m15s 0s

Timeline

0s10s20s30s40s50s1m1m10s