{"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, time, timedelta, timezone\nfrom zoneinfo import ZoneInfo\nfrom helpers import parse_datetime, overlaps\n\ndef run(payload, policy):\n    if not isinstance(payload, dict):\n        return {'selected': [], 'blocked': [], 'rejected': []}\n    appointments = payload.get('appointments') or []\n    tz = ZoneInfo(policy.get('timezone', 'UTC'))\n    duration_max = policy.get('duration_max')\n    lead_minutes = policy.get('lead_minutes', 0)\n    cutoff_hour = policy.get('cutoff_hour', 0)\n    cutoff_inclusive = policy.get('cutoff_inclusive', False)\n    blackout_day = policy.get('blackout_day')\n    cancelled_blocks = policy.get('cancelled_blocks', False)\n    capacity = policy.get('capacity', 1)\n    adjacency_allowed = policy.get('adjacency_allowed', True)\n    duplicate_policy = policy.get('duplicate_policy', 'first')\n    priority_high_first = policy.get('priority_high_first', True)\n    report_order = policy.get('report_order', 'input')\n    now_dt = parse_datetime(payload.get('now'))\n    retained = {}\n    order_keys = []\n    for idx, item in enumerate(appointments):\n        if not isinstance(item, dict):\n            continue\n        appt_id = item.get('id')\n        if appt_id is None:\n            continue\n        if appt_id not in retained:\n            retained[appt_id] = (idx, item)\n            order_keys.append(appt_id)\n        elif duplicate_policy == 'last':\n            retained[appt_id] = (idx, item)\n    selected = []\n    blocked = []\n    rejected = []\n    accepted_intervals = []\n    rows = []\n    for appt_id in order_keys:\n        idx, item = retained[appt_id]\n        rows.append((idx, item))\n    valid_rows = []\n    for idx, item in rows:\n        appt_id = item.get('id')\n        start_dt = parse_datetime(item.get('start'))\n        duration = item.get('duration')\n        priority = item.get('priority')\n        cancelled = item.get('cancelled', False)\n        valid = True\n        if not isinstance(appt_id, str) or not appt_id:\n            valid = False\n        if start_dt is None or now_dt is None:\n            valid = False\n        if isinstance(duration, bool) or not isinstance(duration, int):\n            valid = False\n        elif duration <= 0 or (duration_max is not None and duration > duration_max):\n            valid = False\n        if isinstance(priority, bool) or not isinstance(priority, int):\n            valid = False\n        if not isinstance(cancelled, bool):\n            valid = 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=duration)\n        earliest = now_dt.astimezone(timezone.utc) + timedelta(minutes=lead_minutes)\n        if start_utc < earliest:\n            rejected.append((appt_id, idx))\n            continue\n        start_local = start_dt.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        cutoff_local = datetime.combine(start_local.date(), time(hour=int(cutoff_hour), minute=0), tzinfo=tz)\n        if cutoff_inclusive:\n            if not (end_utc <= cutoff_local):\n                rejected.append((appt_id, idx))\n                continue\n        else:\n            if not (end_utc < cutoff_local):\n                rejected.append((appt_id, idx))\n                continue\n        valid_rows.append((idx, item, start_utc, end_utc, priority, cancelled))\n    if priority_high_first:\n        valid_rows_sorted = sorted(valid_rows, key=lambda r: (-r[4], r[0]))\n    else:\n        valid_rows_sorted = sorted(valid_rows, key=lambda r: (r[4], r[0]))\n    for idx, item, start_utc, end_utc, priority, cancelled in valid_rows_sorted:\n        appt_id = item.get('id')\n        if cancelled and not cancelled_blocks:\n            rejected.append((appt_id, idx))\n            continue\n        count = 0\n        for other_start, other_end in accepted_intervals:\n            if overlaps(start_utc, end_utc, other_start, other_end, adjacency_allowed):\n                count += 1\n        if count >= capacity:\n            rejected.append((appt_id, idx))\n            continue\n        accepted_intervals.append((start_utc, end_utc))\n        if cancelled:\n            blocked.append((appt_id, idx))\n        else:\n            selected.append((appt_id, idx))\n    def order_output(entries):\n        if report_order == 'id':\n            ordered = sorted(entries, key=lambda e: e[0])\n        else:\n            ordered = sorted(entries, key=lambda e: e[1])\n        return [appt_id for appt_id, _ in ordered]\n    return {'selected': order_output(selected), 'blocked': order_output(blocked), 'rejected': order_output(rejected)}\n", "policy.py": "POLICY = {\n    'adjacency_allowed': False,\n    'blackout_day': '2026-11-02',\n    'cancelled_blocks': False,\n    'capacity': 2,\n    'cutoff_hour': 18,\n    'cutoff_inclusive': False,\n    'duplicate_policy': 'last',\n    'duration_max': 90,\n    'lead_minutes': 60,\n    'priority_high_first': False,\n    'report_order': 'input',\n    'timezone': 'UTC',\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 text.endswith(('Z', 'z')):\n            text = text[:-1] + '+00:00'\n        try:\n            dt = datetime.fromisoformat(text)\n        except ValueError:\n            return None\n    else:\n        return None\n    if dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None:\n        return None\n    return dt\n\ndef overlaps(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"}}