{"files": {"main.py": "from core import run\nfrom policy import POLICY\ndef evaluate(payload):\n    return run(payload, POLICY)\n", "core.py": "from datetime import datetime, timedelta, timezone\nfrom zoneinfo import ZoneInfo\nfrom helpers import parse_datetime, intervals_overlap, id_sort_key\n\ndef run(payload, policy):\n    policy = policy or {}\n    if not isinstance(payload, dict):\n        return {'selected': [], 'blocked': [], 'rejected': []}\n    appointments = payload.get('appointments')\n    if not isinstance(appointments, list):\n        appointments = []\n    duplicate_policy = policy.get('duplicate_policy', 'first')\n    retained = {}\n    for idx, appt in enumerate(appointments):\n        if not isinstance(appt, dict):\n            continue\n        if 'id' not in appt:\n            continue\n        appt_id = appt.get('id')\n        try:\n            hash(appt_id)\n        except Exception:\n            continue\n        if duplicate_policy == 'last':\n            retained[appt_id] = (idx, appt)\n        else:\n            if appt_id not in retained:\n                retained[appt_id] = (idx, appt)\n    entries = [(idx, appt.get('id'), appt) for appt_id, (idx, appt) in retained.items()]\n    selected = []\n    blocked = []\n    rejected = []\n    now_dt = parse_datetime(payload.get('now'))\n    if now_dt is None:\n        rejected.extend((appt_id, idx) for idx, appt_id, appt in entries)\n        return _report(selected, blocked, rejected, policy)\n    try:\n        tz = ZoneInfo(policy.get('timezone', 'UTC'))\n    except Exception:\n        tz = timezone.utc\n    lead_minutes = policy.get('lead_minutes', 0)\n    duration_max = policy.get('duration_max')\n    cutoff_hour = policy.get('cutoff_hour', 17)\n    cutoff_inclusive = policy.get('cutoff_inclusive', True)\n    cancelled_blocks = policy.get('cancelled_blocks', False)\n    blackout_day = policy.get('blackout_day')\n    earliest = now_dt.astimezone(timezone.utc) + timedelta(minutes=lead_minutes)\n    candidates = []\n    for idx, appt_id, appt in entries:\n        start_dt = parse_datetime(appt.get('start'))\n        duration = _get_duration(appt)\n        priority = appt.get('priority')\n        cancelled = appt.get('cancelled', False)\n        valid = True\n        if start_dt is None:\n            valid = False\n        if duration is None:\n            valid = False\n        else:\n            try:\n                if not (duration > 0):\n                    valid = False\n                if duration_max is not None and duration > duration_max:\n                    valid = False\n            except Exception:\n                valid = False\n        if isinstance(priority, bool) or not isinstance(priority, int):\n            if isinstance(priority, float) and priority.is_integer():\n                priority = int(priority)\n            else:\n                valid = False\n        if not isinstance(cancelled, bool):\n            valid = False\n            cancelled = False\n        if not valid:\n            rejected.append((appt_id, idx))\n            continue\n        start_utc = start_dt.astimezone(timezone.utc)\n        end_utc = start_utc + timedelta(minutes=float(duration))\n        if start_utc < earliest:\n            rejected.append((appt_id, idx))\n            continue\n        start_local = start_utc.astimezone(tz)\n        if blackout_day is not None and start_local.date().isoformat() == str(blackout_day):\n            rejected.append((appt_id, idx))\n            continue\n        try:\n            cutoff_dt = datetime(start_local.year, start_local.month, start_local.day, int(cutoff_hour), 0, tzinfo=tz)\n        except Exception:\n            rejected.append((appt_id, idx))\n            continue\n        if cutoff_inclusive:\n            if not (end_utc <= cutoff_dt):\n                rejected.append((appt_id, idx))\n                continue\n        else:\n            if not (end_utc < cutoff_dt):\n                rejected.append((appt_id, idx))\n                continue\n        if cancelled and not cancelled_blocks:\n            rejected.append((appt_id, idx))\n            continue\n        candidates.append((priority, idx, appt_id, start_utc, end_utc, cancelled))\n    if policy.get('priority_high_first', False):\n        candidates.sort(key=lambda x: (-x[0], x[1]))\n    else:\n        candidates.sort(key=lambda x: (x[0], x[1]))\n    capacity = policy.get('capacity', 1)\n    try:\n        capacity = int(capacity)\n    except Exception:\n        capacity = 1\n    adjacency_allowed = policy.get('adjacency_allowed', True)\n    accepted = []\n    for priority, idx, appt_id, start_utc, end_utc, cancelled in candidates:\n        count = 0\n        for a_start, a_end in accepted:\n            if intervals_overlap(start_utc, end_utc, a_start, a_end, adjacency_allowed):\n                count += 1\n        if count < capacity:\n            accepted.append((start_utc, end_utc))\n            if cancelled:\n                blocked.append((appt_id, idx))\n            else:\n                selected.append((appt_id, idx))\n        else:\n            rejected.append((appt_id, idx))\n    return _report(selected, blocked, rejected, policy)\n\ndef _get_duration(appt):\n    if 'duration_minutes' in appt:\n        value = appt.get('duration_minutes')\n    elif 'duration' in appt:\n        value = appt.get('duration')\n    elif 'duration_mins' in appt:\n        value = appt.get('duration_mins')\n    elif 'duration_min' in appt:\n        value = appt.get('duration_min')\n    else:\n        return None\n    if isinstance(value, bool) or not isinstance(value, (int, float)):\n        return None\n    if isinstance(value, float) and (value != value or value in (float('inf'), float('-inf'))):\n        return None\n    return value\n\ndef _report(selected, blocked, rejected, policy):\n    return {'selected': _order(selected, policy), 'blocked': _order(blocked, policy), 'rejected': _order(rejected, policy)}\n\ndef _order(items, policy):\n    if policy.get('report_order', 'id') == 'id':\n        ordered = sorted(items, key=lambda x: id_sort_key(x[0]))\n    else:\n        ordered = sorted(items, key=lambda x: x[1])\n    return [appt_id for appt_id, idx in ordered]\n", "policy.py": "POLICY = {\n    'timezone': 'America/New_York',\n    'cutoff_hour': 17,\n    'cutoff_inclusive': True,\n    'lead_minutes': 30,\n    'adjacency_allowed': True,\n    'duration_max': 120,\n    'duplicate_policy': 'first',\n    'cancelled_blocks': True,\n    'capacity': 1,\n    'report_order': 'id',\n    'blackout_day': '2026-11-01',\n    'priority_high_first': True,\n}\n", "helpers.py": "from datetime import datetime\n\ndef parse_datetime(value):\n    if isinstance(value, datetime):\n        dt = value\n    elif isinstance(value, str):\n        text = value.strip()\n        if not text:\n            return None\n        if text.endswith('Z') or text.endswith('z'):\n            text = text[:-1] + '+00:00'\n        try:\n            dt = datetime.fromisoformat(text)\n        except Exception:\n            return None\n    else:\n        return None\n    if dt.tzinfo is None:\n        return None\n    try:\n        if dt.utcoffset() is None:\n            return None\n    except Exception:\n        return None\n    return dt\n\ndef intervals_overlap(start, end, other_start, other_end, adjacency_allowed):\n    if adjacency_allowed:\n        return start < other_end and other_start < end\n    return start <= other_end and other_start <= end\n\ndef id_sort_key(value):\n    if isinstance(value, bool):\n        return (1, 0, str(value))\n    if isinstance(value, (int, float)):\n        return (0, value, '')\n    return (1, 0, str(value))\n"}}