Design notes on the choices I made:

- **Deduplication:** with policy "first", the first occurrence is kept and its original index is that occurrence's own index. Position is preserved.
- **Processing order:** priority descending, ties by original index.
- **Validation:** an appointment is rejected for bad duration, a start before now+lead, a blackout day, or a cutoff violation. Cancelled appointments are checked the same way. If `cancelled_blocks` is true, a valid cancelled appointment may reserve capacity and goes to `blocked`, otherwise it is rejected.
- **Capacity:** an appointment is accepted if the count of accepted intervals that overlap it is below capacity. Accepted intervals include cancelled ones that reserved capacity. With adjacency allowed, overlap means `s < e2 and s2 < e`.
- **Conflicts:** an appointment that fails the capacity check goes to rejected.
- **Time arithmetic:** UTC is used for the arithmetic. The cutoff is computed as a local datetime built with `zoneinfo` on the start's local date at 17:00, then converted to UTC for comparison.
- **Output ordering:** sorted by id (report_order "id").

```json
{"files": {"main.py": "from core import run\nfrom policy import POLICY\ndef evaluate(payload):\n    return run(payload, POLICY)\n", "policy.py": "POLICY = {\"adjacency_allowed\": True, \"blackout_day\": \"2026-11-01\", \"cancelled_blocks\": True, \"capacity\": 1, \"cutoff_hour\": 17, \"cutoff_inclusive\": True, \"duplicate_policy\": \"first\", \"duration_max\": 120, \"lead_minutes\": 30, \"priority_high_first\": True, \"report_order\": \"id\", \"timezone\": \"America/New_York\"}\n", "helpers.py": "from datetime import datetime, timedelta, timezone\n\ndef parse(s):\n    if isinstance(s, str) and s.endswith('Z'):\n        s = s[:-1] + '+00:00'\n    return datetime.fromisoformat(s)\n\ndef overlaps(s1, e1, s2, e2, adjacency_allowed):\n    if adjacency_allowed:\n        return s1 < e2 and s2 < e1\n    return s1 <= e2 and s2 <= e1\n", "core.py": "from datetime import datetime, timedelta, timezone\nfrom zoneinfo import ZoneInfo\nfrom helpers import parse, overlaps\n\ndef run(payload, policy):\n    tz = ZoneInfo(policy['timezone'])\n    utc = timezone.utc\n    now = parse(payload['now']).astimezone(utc)\n    rows = {}\n    order = []\n    for i, a in enumerate(payload['appointments']):\n        k = a['id']\n        if k not in rows:\n            order.append(k)\n            rows[k] = (i, a)\n        elif policy['duplicate_policy'] == 'last':\n            rows[k] = (i, a)\n    items = [rows[k] for k in order]\n    hi = policy['priority_high_first']\n    items.sort(key=lambda t: ((-t[1]['priority'] if hi else t[1]['priority']), t[0]))\n    selected, blocked, rejected = [], [], []\n    accepted = []\n    lead = timedelta(minutes=policy['lead_minutes'])\n    for idx, a in items:\n        aid = a['id']\n        dur = a['duration']\n        if isinstance(dur, bool) or not isinstance(dur, int) or dur <= 0 or dur > policy['duration_max']:\n            rejected.append((idx, aid)); continue\n        try:\n            start_utc = parse(a['start']).astimezone(utc)\n        except Exception:\n            rejected.append((idx, aid)); continue\n        end_utc = start_utc + timedelta(minutes=dur)\n        if start_utc < now + lead:\n            rejected.append((idx, aid)); continue\n        local = start_utc.astimezone(tz)\n        if local.date().isoformat() == policy['blackout_day']:\n            rejected.append((idx, aid)); continue\n        cutoff = datetime(local.year, local.month, local.day, policy['cutoff_hour'], 0, tzinfo=tz).astimezone(utc)\n        if policy['cutoff_inclusive']:\n            ok = end_utc <= cutoff\n        else:\n            ok = end_utc < cutoff\n        if not ok:\n            rejected.append((idx, aid)); continue\n        if a['cancelled'] and not policy['cancelled_blocks']:\n            rejected.append((idx, aid)); continue\n        cnt = 0\n        for s2, e2 in accepted:\n            if overlaps(start_utc, end_utc, s2, e2, policy['adjacency_allowed']):\n                cnt += 1\n        if cnt >= policy['capacity']:\n            rejected.append((idx, aid)); continue\n        accepted.append((start_utc, end_utc))\n        if a['cancelled']:\n            blocked.append((idx, aid))\n        else:\n            selected.append((idx, aid))\n    def fmt(lst):\n        if policy['report_order'] == 'id':\n            return sorted(x[1] for x in lst)\n        return [x[1] for x in sorted(lst)]\n    return {'selected': fmt(selected), 'blocked': fmt(blocked), 'rejected': fmt(rejected)}\n"}}
```