e35f9993

ical: report a recurrence rule that specifies both UNTIL and COUNT

There was a `TODO` asking for this. Checking it turned up two more problems in the same six lines.

## The missing error

RFC 5545 §3.3.10:

> The UNTIL or COUNT rule parts are OPTIONAL,
> but they MUST NOT occur in the same 'recur'.

`parseRecurrenceRule` accepted both, kept one, and said nothing, so a conforming run could not tell the input was non-conforming. Now a fixable error: strict parsing refuses such a rule, lenient parsing keeps the COUNT.

Neither part is ambiguous on its own, which is why this is fixable rather than unfixable — one is kept and the other reported.

## The swapped bindings

```haskell
recurrenceRuleUntilCount :: !(Maybe (Either Until Count))
```

`Right` is the count. But the code read:

```haskell
mUntil <- parseMPart
mCount <- parseMPart
let recurrenceRuleUntilCount = case (mUntil, mCount) of
      (Nothing, Nothing) -> Nothing
      (Nothing, Just c) -> Just (Left c)
      -- Don't reject invalid ical that defines both, but ignore the count.
      -- TODO emit a fixable warning here.
      (Just u, _) -> Just (Right u)
```

`parseMPart` picks its rule part from the type it is used at, so `mUntil` was bound to the parsed **COUNT** (it feeds `Right`) and `mCount` to the parsed **UNTIL**. The names each said the other one's value.

## The false comment

Given the above, the both-specified case keeps the COUNT and drops the UNTIL — the opposite of what its comment claimed. Confirmed before changing anything:

```
RRULE:FREQ=DAILY;UNTIL=20200201T000000Z;COUNT=3
  -> Just (Right (Count {unCount = 3}))
```

Which one wins is arbitrary, because the spec does not say. **The COUNT still wins** — no behaviour change there, it is just now stated out loud, pinned by a test, and the case enumerates all four combinations instead of falling through, so the compiler checks which part survives.

Same reasoning as #30 for colliding time zone observances: arbitrary is fine as long as it is deterministic and written down.

## Two commits

1. **Red.** Two fail: the new `calendar/fixable` scenario's `cannot parse this calendar strictly`, and `does not parse without fixing something`. The third test, `keeps the count and drops the until when parsed leniently`, passes before and after — it is there to pin the arbitrary choice.
2. **Green.**

## Note on the error payload

`RecurrenceRuleHasBothUntilAndCount` carries the two values as the text they were written as. `Until` and `Count` would say it better, but they are defined in a module that imports the one where `PropertyTypeFixableError` lives.

## Checks

The calendar goes in `test_resources/calendar/fixable`, so the existing pair of scenario tests covers it: strict parsing must refuse it, and lenient parsing must produce something valid that then parses strictly.

`ical-gen` 1082 → 1088 passing, 0 failing. `ical-recurrence-gen` unchanged. `nix flake check` passed before the rebase onto current master; rebased cleanly and re-verified with both suites.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 7m13s 1s 1s 7m14s 7m13s
Eval 8m10s 19s 19s 8m29s 55s
Build 8m29s 2s 31m48s 40m18s 31m45s
Suite 7m13s 23s 33m04s 40m18s 39m54s

Timeline

0s8m20s