aaebf436

Reconcile the components of a UID when importing a calendar

A component with a `RECURRENCE-ID` replaces the instance of its series that it names rather than adding an occurrence beside it, and Google and Outlook write one for every "this event only" edit. Recurring one component at a time cannot know that, so the edited instance was imported **twice**: once where it used to be and once where it now is.

## `deduplicateBasedOnId` is deleted

It was the hand-rolled version of this feature: sort groups by their descending first occurrence on the theory that the earliest-starting group is the original, then drop any occurrence already seen. Because the key was the *whole* occurrence — start **and** end — it only worked when the override changed neither, which is the uncommon case. Move the override's `DTEND` by a minute and the duplicate came back. It also deduplicated across UIDs, which nothing justifies.

[ical-recurrence 0.3.0.0](https://github.com/NorfairKing/ical/pull/43) reconciles a UID's components, so the library does this now, and correctly.

## What moved

`RecurringEvents` has to carry what reconciliation needs from each component, so `RecurringEvent` gains its `SEQUENCE` and its `RECURRENCE-ID`. There is still no `uid` field, because the map is keyed by it; `recurringOf` puts the two back together for `ICal.recur`. **Both new fields are omitted at their defaults, so an old picked file still parses and means what it used to** — existing caches keep working.

The pipeline keeps its shape of one `Static` plus a set of start/end pairs. What changes is the grouping key: reconciliation can put occurrences from two different components in one UID's recurrence set, and each occurrence carries the component it came from, so `Recur` groups by that component rather than by UID. `ResolveZones` and everything below it are unchanged apart from renamed types.

`Pick` can no longer drop the components it does not want, so `Static` gains an `Inclusion` and `Recur` drops the excluded occurrences after reconciliation instead. Both filters need this:

- `STATUS:CANCELLED` on a component with a `RECURRENCE-ID` is how "delete this one instance" is written. Dropping that component before the recurrence set is reconciled makes the series' instance **reappear** at that time instead of disappearing — a live bug.
- `SMOS_NO_CALENDAR_IMPORT` is a per-component opt-out, and an overriding component has a description of its own.

## Goldens

All checked by hand against a separately derived expectation.

| File | Why |
| --- | --- |
| `recurrence-id.*` | **New.** The case that matters: a conforming `RECURRENCE-ID` moving one instance of a weekly series. Its `.unresolved` shows the series keeping the instances it still has, and no longer the overridden one. |
| `uid.*` | Keeps its malformed `RECURRENCE-ID` — zoned where the series' `DTSTART` is floating (§3.8.4.4 forbids that) and naming a Friday where the series generates Mondays. It matches no instance, so it is now an orphan: the override is kept, the series still produces the instance it failed to name, and `RecurrenceIdentifierUnmatched` says the input needs fixing. One more occurrence than before — and the old output was luck, not correctness: `deduplicateBasedOnId` happened to drop the series' instance because the override's start and end were byte-identical to it. |
| `ignored.recurring` | No longer empty: the component is picked with `include: false` rather than dropped. Everything downstream of it is still empty. |
| `museum.recurring`, `exception.recurring` | Gain a `sequence` field; those two components have a `SEQUENCE` other than 0. |

Three more move for the `ical` bump alone rather than anything here: `museum.parsed` and `visit.parsed` gain the `X-WR-TIMEZONE` those calendars always had and the library now round-trips, and `zoned-recurring.unresolved` loses a duplicate instance — the already-fixed bug where `DTSTART` and the recurrence rule both produced the first instance with two different ends.

`stack test smos-calendar-import --pedantic`: 183 passed, 0 failed.
PR #303
Time to Start Worker time Duration Time to finish Idle
Config 1s 1s 1s 2s 1s
Eval 37s 28s 28s 1m06s 35s
Build 1m03s 23m28s - - 6m22s
Suite 1s 23m58s - - 2h37m19s