a25556aa

ical-recurrence: cover VTODO and VJOURNAL, and release 0.3.0.0

**4 of 4**, the last one. Sequence: `recurrence-types` (#44) → `recurrence-id` (#45) → `this-and-future` (#46) → **this**.

The last of the `RECURRENCE-ID` sequence (#40, #41, #42). Coverage plus the release. **Nothing here is red** — the projections these exercise landed with the type refactor and the reconciliation; this is the coverage they did not have.

## VTODO and VJOURNAL scenarios

`test_resources/todo` and `test_resources/journal` are siblings of `test_resources/event` and pin the one thing that differs between the three component kinds: where the end of an instance comes from.

A `VTODO` ends at its `DUE` where a `VEVENT` ends at its `DTEND`. The two properties agree on their value type and on what recurrence does with them, so an occurrence carries whichever of them the component spelled, as one `RecurrenceEnd`, and the golden format writes it back out as a `DTEND` line either way. A `VJOURNAL` has no such property at all, so its occurrences have no end and the golden leaves that line empty.

Four goldens, each derived by hand before being compared against the generated one:

| Fixture | What it pins |
| --- | --- |
| `todo/due.ics` | `DUE` carried across instances the way a `DTEND` is |
| `todo/duration.ics` | an all-day to-do with a `DURATION` instead |
| `journal/weekly.ics` | a journal entry recurring with no end at all |
| `journal/rdate.ics` | `RDATE` and `EXDATE` on a journal entry |

## recurCalendar

One test, for what only `recurCalendar` can get wrong: a UID names a recurrence set *within* one kind of component rather than across them, so the same UID on a `VEVENT`, a `VTODO` and a `VJOURNAL` is three recurrence sets and not one. Resolving its zoned starts afterwards is also what shows that `runCalendarR` supplied the time zone the calendar defines.

`VFREEBUSY` gets no projection because it has no recurrence properties, and `VTIMEZONE` observances go through `timeZoneRuleOccurrences` instead — shout if you expected either of those to be in scope.

## Release

`ical-recurrence` 0.2.0.0 → **0.3.0.0**. Every name in the deleted API is either gone or has an incompatible type, so this is a major bump. `ical` itself does not change: `Recurring`, `RecurrenceEnd`, `Occurrence` and `Resolved` all live in `ical-recurrence`, and the three projection functions only read fields `ical` already had.

The changelog entry covers the whole sequence — the duplicate occurrence that started it, why the API is now expressed over collections, the replaced names, and the new error constructors for anyone matching on them exhaustively.

---

Previously opened as #43 and merged by mistake without review. Same two commits, rebased onto the new `master`; the rebase left content byte-identical. Re-checked after rebasing: 331 passing / 0 failing / 1 pending, no pre-existing golden modified, the version is consistent across `package.yaml`, the tracked `.cabal` and `default.nix`, the changelog cites no PR numbers (so the renumbering does not stale it), and regenerating the four new goldens with `--golden-reset` changes nothing.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 0s 1s 1s 1s 0s
Eval 0s 9s 9s 10s 0s
Build 9s 0s 0s 9s 0s
Suite 0s 10s 10s 10s 0s

Timeline

0s10s