{"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, intervals_overlap, make_cutoff\n\ndef run(payload, policy):\n    selected = []\n    blocked = []\n    rejected = []\n    rejected_index = {}\n    if not isinstance(payload, dict):\n        return {'selected': [], 'blocked': [], 'rejected': []}\n    policy = policy or {}\n    try:\n        tz = ZoneInfo(policy.get('timezone', 'America/New_York'))\n    except Exception:\n        tz = None\n    appointments = payload.get('appointments')\n    if not isinstance(appointments, list):\n        appointments = []\n    duplicate_policy = policy.get('duplicate_policy', 'first')\n    dedup = {}\n    order = []\n    for idx, appt in enumerate(appointments):\n        if not isinstance(appt, dict):\n            continue\n        appt_id = appt.get('id')\n        try:\n            hash(appt_id)\n        except Exception:\n            continue\n        if appt_id not in dedup:\n            dedup[appt_id] = (idx, appt)\n            order.append(appt_id)\n        elif duplicate_policy == 'last':\n            dedup[appt_id] = (idx, appt)\n    retained = []\n    for appt_id in order:\n        idx, appt = dedup[appt_id]\n        retained.append((idx, appt))\n    index_by_id = {appt.get('id'): idx for idx, appt in retained}\n    def add_rejected(appt_id):\n        rejected.append(appt_id)\n        if appt_id in index_by_id:\n            rejected_index[appt_id] = index_by_id[appt_id]\n    now = parse_aware(payload.get('now')) if 'now' in payload else None\n    lead_minutes = policy.get('lead_minutes', 30)\n    duration_max = policy.get('duration_max', 120)\n    blackout_day = policy.get('blackout_day')\n    cutoff_hour = policy.get('cutoff_hour', 17)\n    cutoff_inclusive = policy.get('cutoff_inclusive', True)\n    cancelled_blocks = policy.get('cancelled_blocks', True)\n    capacity = policy.get('capacity', 1)\n    adjacency_allowed = policy.get('adjacency_allowed', True)\n    priority_high_first = policy.get('priority_high_first', True)\n    candidates = []\n    if tz is None or now is None:\n        for idx, appt in retained:\n            if isinstance(appt.get('id'), str):\n                add_rejected(appt.get('id'))\n    else:\n        earliest = now.astimezone(timezone.utc) + timedelta(minutes=lead_minutes)\n        for idx, appt in retained:\n            appt_id = appt.get('id')\n            if not isinstance(appt_id, str) or appt_id == '':\n                if isinstance(appt_id, str):\n                    add_rejected(appt_id)\n                continue\n            start = parse_aware(appt.get('start'))\n            duration = appt.get('duration')\n            priority = appt.get('priority')\n            cancelled = appt.get('cancelled')\n            valid = True\n            if start is None:\n                valid = False\n            if isinstance(duration, bool) or not isinstance(duration, (int, float)):\n                valid = False\n            elif isinstance(duration, float) and (duration != duration or duration in (float('inf'), float('-inf'))):\n                valid = False\n            elif not (duration > 0 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                add_rejected(appt_id)\n                continue\n            start_utc = start.astimezone(timezone.utc)\n            end_utc = start_utc + timedelta(minutes=duration)\n            if start_utc < earliest:\n                add_rejected(appt_id)\n                continue\n            local_start = start_utc.astimezone(tz)\n            if blackout_day is not None and local_start.date().isoformat() == str(blackout_day):\n                add_rejected(appt_id)\n                continue\n            try:\n                cutoff = make_cutoff(local_start.date(), cutoff_hour, tz)\n            except Exception:\n                add_rejected(appt_id)\n                continue\n            cutoff_utc = cutoff.astimezone(timezone.utc)\n            if cutoff_inclusive:\n                if not (end_utc <= cutoff_utc):\n                    add_rejected(appt_id)\n                    continue\n            else:\n                if not (end_utc < cutoff_utc):\n                    add_rejected(appt_id)\n                    continue\n            if cancelled and not cancelled_blocks:\n                add_rejected(appt_id)\n                continue\n            candidates.append({'id': appt_id, 'index': idx, 'priority': priority, 'cancelled': cancelled, 'start': start_utc, 'end': end_utc})\n    if priority_high_first:\n        candidates_sorted = sorted(candidates, key=lambda c: (-c['priority'], c['index']))\n    else:\n        candidates_sorted = sorted(candidates, key=lambda c: (c['priority'], c['index']))\n    accepted = []\n    for cand in candidates_sorted:\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'])\n            else:\n                selected.append(cand['id'])\n        else:\n            add_rejected(cand['id'])\n    report_order = policy.get('report_order', 'id')\n    if report_order == 'id':\n        selected = sorted(selected)\n        blocked = sorted(blocked)\n        rejected = sorted(rejected)\n    else:\n        selected = sorted(selected, key=lambda i: index_by_id.get(i, 0))\n        blocked = sorted(blocked, key=lambda i: index_by_id.get(i, 0))\n        rejected = sorted(rejected, key=lambda i: rejected_index.get(i, index_by_id.get(i, 0)))\n    return {'selected': selected, 'blocked': blocked, 'rejected': rejected}\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\n\ndef parse_aware(value):\n    if not isinstance(value, str):\n        return None\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    if parsed.tzinfo is None or parsed.utcoffset() is None:\n        return None\n    return parsed\n\ndef intervals_overlap(start1, end1, start2, end2, adjacency_allowed):\n    if adjacency_allowed:\n        return start1 < end2 and start2 < end1\n    return start1 <= end2 and start2 <= end1\n\ndef make_cutoff(local_date, cutoff_hour, tz):\n    return datetime(local_date.year, local_date.month, local_date.day, int(cutoff_hour), 0, tzinfo=tz)\n"}}