{"files":{"main.py":"from core import run\nfrom policy import POLICY\n\n\ndef evaluate(payload):\n    return run(payload, POLICY)\n","core.py":"from datetime import timedelta\nfrom zoneinfo import ZoneInfo\n\nfrom helpers import normalize, overlaps, parse_datetime\n\n\ndef run(payload, policy):\n    now = parse_datetime(payload['now'])\n    earliest = now + timedelta(minutes=policy['lead_minutes'])\n    zone = ZoneInfo(policy['timezone'])\n\n    retained = {}\n    for index, row in enumerate(payload['appointments']):\n        appointment_id = row['id']\n        if appointment_id not in retained or policy['duplicate_policy'] == 'last':\n            retained[appointment_id] = (index, row)\n\n    results = {'selected': [], 'blocked': [], 'rejected': []}\n    candidates = []\n    for appointment_id, (index, row) in retained.items():\n        candidate = normalize(row, index, earliest, zone, policy)\n        if candidate is None:\n            results['rejected'].append((index, appointment_id))\n        else:\n            candidate['id'] = appointment_id\n            candidates.append(candidate)\n\n    candidates.sort(key=lambda item: (\n        -item['priority'] if policy['priority_high_first'] else item['priority'],\n        item['index'],\n    ))\n\n    accepted = []\n    for candidate in candidates:\n        count = sum(\n            overlaps(candidate, previous, policy['adjacency_allowed'])\n            for previous in accepted\n        )\n        if count >= policy['capacity']:\n            destination = 'rejected'\n        else:\n            accepted.append(candidate)\n            destination = 'blocked' if candidate['cancelled'] else 'selected'\n        results[destination].append((candidate['index'], candidate['id']))\n\n    for destination, entries in results.items():\n        entries.sort(key=lambda entry: entry[1] if policy['report_order'] == 'id' else entry[0])\n        results[destination] = [appointment_id for _, appointment_id in entries]\n    return results\n","policy.py":"POLICY = {\n    'timezone': 'UTC',\n    'cutoff_hour': 18,\n    'cutoff_inclusive': False,\n    'lead_minutes': 60,\n    'adjacency_allowed': False,\n    'duration_max': 90,\n    'duplicate_policy': 'last',\n    'cancelled_blocks': False,\n    'blackout_day': '2026-11-02',\n    'priority_high_first': False,\n    'capacity': 2,\n    'report_order': 'input',\n}\n","helpers.py":"from datetime import datetime, time, timedelta, timezone\nfrom math import isfinite\n\n\ndef parse_datetime(value):\n    if not isinstance(value, str):\n        raise ValueError('Expected an offset-aware ISO datetime string')\n    parsed = datetime.fromisoformat(value)\n    if parsed.tzinfo is None or parsed.utcoffset() is None:\n        raise ValueError('Datetime must include an offset')\n    return parsed.astimezone(timezone.utc)\n\n\ndef normalize(row, index, earliest, zone, policy):\n    try:\n        duration = row['duration']\n        priority = row['priority']\n        cancelled = row['cancelled']\n        if isinstance(duration, bool) or not isinstance(duration, (int, float)):\n            return None\n        if not isfinite(duration) or not 0 < duration <= policy['duration_max']:\n            return None\n        if isinstance(priority, bool) or not isinstance(priority, int):\n            return None\n        if not isinstance(cancelled, bool):\n            return None\n        if cancelled and not policy['cancelled_blocks']:\n            return None\n\n        start = parse_datetime(row['start'])\n        end = start + timedelta(minutes=duration)\n        if start < earliest:\n            return None\n        local_start = start.astimezone(zone)\n        if local_start.date().isoformat() == policy['blackout_day']:\n            return None\n        cutoff = datetime.combine(\n            local_start.date(), time(hour=policy['cutoff_hour']), tzinfo=zone\n        ).astimezone(timezone.utc)\n        if policy['cutoff_inclusive']:\n            if end > cutoff:\n                return None\n        elif end >= cutoff:\n            return None\n        return {\n            'index': index,\n            'start': start,\n            'end': end,\n            'priority': priority,\n            'cancelled': cancelled,\n        }\n    except (KeyError, TypeError, ValueError, OverflowError):\n        return None\n\n\ndef overlaps(left, right, adjacency_allowed):\n    if adjacency_allowed:\n        return left['start'] < right['end'] and right['start'] < left['end']\n    return left['start'] <= right['end'] and right['start'] <= left['end']\n"}}