{"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_aware_datetime, intervals_overlap\n\ndef run(payload, policy):\n    result = {'selected': [], 'blocked': [], 'rejected': []}\n    if not isinstance(payload, dict):\n        return result\n    if not isinstance(policy, dict):\n        policy = {}\n    timezone_name = policy.get('timezone', 'America/New_York')\n    cutoff_hour = policy.get('cutoff_hour', 17)\n    cutoff_inclusive = policy.get('cutoff_inclusive', True)\n    lead_minutes = policy.get('lead_minutes', 30)\n    duration_max = policy.get('duration_max', 120)\n    capacity = policy.get('capacity', 1)\n    adjacency_allowed = policy.get('adjacency_allowed', True)\n    cancelled_blocks = policy.get('cancelled_blocks', True)\n    duplicate_policy = policy.get('duplicate_policy', 'first')\n    blackout_day = policy.get('blackout_day', '2026-11-01')\n    priority_high_first = policy.get('priority_high_first', True)\n    report_order = policy.get('report_order', 'id')\n    try:\n        tz = ZoneInfo(timezone_name)\n    except Exception:\n        tz = None\n    appointments = payload.get('appointments')\n    if not isinstance(appointments, list):\n        return result\n    retained = {}\n    order = []\n    for idx, entry in enumerate(appointments):\n        if not isinstance(entry, dict):\n            continue\n        if 'id' not in entry:\n            continue\n        ident = entry.get('id')\n        if isinstance(ident, bool) or not isinstance(ident, (str, int)):\n            continue\n        if isinstance(ident, str) and ident == '':\n            continue\n        if ident in retained:\n            if duplicate_policy == 'last':\n                retained[ident] = (entry, idx)\n            continue\n        retained[ident] = (entry, idx)\n        order.append(ident)\n    selected = []\n    blocked = []\n    rejected = []\n    now = parse_aware_datetime(payload.get('now'))\n    if now is None or tz is None:\n        for ident in order:\n            rejected.append((ident, retained[ident][1]))\n        return _format(selected, blocked, rejected, report_order)\n    now_utc = now.astimezone(timezone.utc)\n    try:\n        earliest = now_utc + timedelta(minutes=lead_minutes)\n    except Exception:\n        for ident in order:\n            rejected.append((ident, retained[ident][1]))\n        return _format(selected, blocked, rejected, report_order)\n    candidates = []\n    for ident in order:\n        entry, idx = retained[ident]\n        valid = True\n        start = parse_aware_datetime(entry.get('start'))\n        duration = entry.get('duration')\n        priority = entry.get('priority')\n        cancelled = entry.get('cancelled')\n        if start is None:\n            valid = False\n        if isinstance(duration, bool) or not isinstance(duration, int):\n            valid = False\n        elif duration <= 0 or 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((ident, idx))\n            continue\n        start_utc = start.astimezone(timezone.utc)\n        end_utc = start_utc + timedelta(minutes=duration)\n        if start_utc < earliest:\n            rejected.append((ident, idx))\n            continue\n        local_start = start_utc.astimezone(tz)\n        if str(blackout_day) == local_start.date().isoformat():\n            rejected.append((ident, idx))\n            continue\n        try:\n            cutoff_local = datetime(local_start.year, local_start.month, local_start.day, int(cutoff_hour), 0, tzinfo=tz)\n        except Exception:\n            rejected.append((ident, idx))\n            continue\n        cutoff_utc = cutoff_local.astimezone(timezone.utc)\n        if cutoff_inclusive:\n            if end_utc > cutoff_utc:\n                rejected.append((ident, idx))\n                continue\n        else:\n            if end_utc >= cutoff_utc:\n                rejected.append((ident, idx))\n                continue\n        if cancelled and not cancelled_blocks:\n            rejected.append((ident, idx))\n            continue\n        candidates.append({'id': ident, 'index': idx, 'start': start_utc, 'end': end_utc, 'priority': priority, 'cancelled': cancelled})\n    if priority_high_first:\n        candidates.sort(key=lambda c: (-c['priority'], c['index']))\n    else:\n        candidates.sort(key=lambda c: (c['priority'], c['index']))\n    accepted = []\n    for cand in candidates:\n        count = 0\n        for other in accepted:\n            if intervals_overlap(cand['start'], cand['end'], other['start'], other['end'], adjacency_allowed):\n                count += 1\n        if count < capacity:\n            accepted.append(cand)\n            if cand['cancelled']:\n                blocked.append((cand['id'], cand['index']))\n            else:\n                selected.append((cand['id'], cand['index']))\n        else:\n            rejected.append((cand['id'], cand['index']))\n    return _format(selected, blocked, rejected, report_order)\n\ndef _format(selected, blocked, rejected, report_order):\n    return {'selected': _sort_list(selected, report_order), 'blocked': _sort_list(blocked, report_order), 'rejected': _sort_list(rejected, report_order)}\n\ndef _sort_list(items, report_order):\n    if report_order == 'id':\n        try:\n            ordered = sorted(items, key=lambda x: x[0])\n        except Exception:\n            ordered = sorted(items, key=lambda x: str(x[0]))\n    else:\n        ordered = sorted(items, key=lambda x: x[1])\n    return [ident for ident, _idx in ordered]\n", "policy.py": "POLICY = {'cutoff_hour': 17, 'cutoff_inclusive': True, 'lead_minutes': 30, 'timezone': 'America/New_York', 'adjacency_allowed': True, 'cancelled_blocks': True, 'duplicate_policy': 'first', 'duration_max': 120, 'capacity': 1, 'report_order': 'id', 'blackout_day': '2026-11-01', 'priority_high_first': True}\n", "helpers.py": "from datetime import datetime\n\ndef parse_aware_datetime(value):\n    if isinstance(value, datetime):\n        parsed = value\n    elif isinstance(value, str):\n        text = value.strip()\n        if text.endswith('Z') or text.endswith('z'):\n            text = text[:-1] + '+00:00'\n        try:\n            parsed = datetime.fromisoformat(text)\n        except Exception:\n            return None\n    else:\n        return None\n    if parsed.tzinfo is None or parsed.utcoffset() is None:\n        return None\n    return parsed\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"}}