{"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 timedelta, timezone\nfrom zoneinfo import ZoneInfo\nfrom helpers import parse_datetime, is_int, overlaps, make_cutoff\n\ndef run(payload, policy):\n    selected = []\n    blocked = []\n    rejected = []\n    if not isinstance(payload, dict):\n        return {'selected': [], 'blocked': [], 'rejected': []}\n    appointments = payload.get('appointments')\n    if not isinstance(appointments, list):\n        return {'selected': [], 'blocked': [], 'rejected': []}\n    duplicate_policy = policy.get('duplicate_policy', 'first')\n    retained = {}\n    for idx, entry in enumerate(appointments):\n        if not isinstance(entry, dict):\n            continue\n        appt_id = entry.get('id')\n        if not isinstance(appt_id, str):\n            continue\n        if duplicate_policy == 'first':\n            if appt_id not in retained:\n                retained[appt_id] = (idx, entry)\n        else:\n            retained[appt_id] = (idx, entry)\n    items = [(idx, entry.get('id'), entry) for idx, entry in [(v[0], v[1]) for v in []]]\n    records = []\n    for appt_id, (idx, entry) in retained.items():\n        records.append({'id': appt_id, 'index': idx, 'entry': dict(entry)})\n    report_order = policy.get('report_order', 'input')\n    def sort_records(recs):\n        if report_order == 'id':\n            return sorted(recs, key=lambda r: r['id'])\n        return sorted(recs, key=lambda r: r['index'])\n    now_dt = parse_datetime(payload.get('now'))\n    if now_dt is None:\n        rejected.extend(records)\n        return {'selected': [r['id'] for r in sort_records(selected)], 'blocked': [r['id'] for r in sort_records(blocked)], 'rejected': [r['id'] for r in sort_records(rejected)]}\n    try:\n        tz = ZoneInfo(policy.get('timezone', 'UTC'))\n    except Exception:\n        tz = timezone.utc\n    duration_max = policy.get('duration_max')\n    lead_minutes = policy.get('lead_minutes', 0)\n    blackout_day = policy.get('blackout_day')\n    cutoff_hour = policy.get('cutoff_hour')\n    cutoff_inclusive = policy.get('cutoff_inclusive', True)\n    cancelled_blocks = policy.get('cancelled_blocks', False)\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    now_utc = now_dt.astimezone(timezone.utc)\n    earliest = now_utc + timedelta(minutes=lead_minutes)\n    candidates = []\n    for rec in records:\n        entry = rec['entry']\n        valid = True\n        start_dt = None\n        duration = entry.get('duration')\n        priority = entry.get('priority')\n        cancelled = entry.get('cancelled')\n        if not is_int(duration) or not is_int(priority) or not isinstance(cancelled, bool):\n            valid = False\n        start_dt = parse_datetime(entry.get('start')) if valid else None\n        if valid and start_dt is None:\n            valid = False\n        if valid and (duration <= 0 or (duration_max is not None and duration > duration_max)):\n            valid = False\n        start_utc = None\n        end_utc = None\n        if valid:\n            start_utc = start_dt.astimezone(timezone.utc)\n            end_utc = start_utc + timedelta(minutes=duration)\n            if start_utc < earliest:\n                valid = False\n        if valid:\n            start_local = start_dt.astimezone(tz)\n            if blackout_day is not None and start_local.date().isoformat() == str(blackout_day):\n                valid = False\n            else:\n                cutoff = make_cutoff(start_local, cutoff_hour, tz)\n                if cutoff_inclusive:\n                    if not (end_utc <= cutoff):\n                        valid = False\n                else:\n                    if not (end_utc < cutoff):\n                        valid = False\n        if valid and cancelled and not cancelled_blocks:\n            valid = False\n        if not valid:\n            rejected.append(rec)\n        else:\n            rec['start_utc'] = start_utc\n            rec['end_utc'] = end_utc\n            rec['priority'] = priority\n            rec['cancelled'] = cancelled\n            candidates.append(rec)\n    if priority_high_first:\n        candidates_sorted = sorted(candidates, key=lambda r: (-r['priority'], r['index']))\n    else:\n        candidates_sorted = sorted(candidates, key=lambda r: (r['priority'], r['index']))\n    accepted_intervals = []\n    for rec in candidates_sorted:\n        count = 0\n        for a_start, a_end in accepted_intervals:\n            if overlaps(rec['start_utc'], rec['end_utc'], a_start, a_end, adjacency_allowed):\n                count += 1\n        if count < capacity:\n            accepted_intervals.append((rec['start_utc'], rec['end_utc']))\n            if rec['cancelled'] and cancelled_blocks:\n                blocked.append(rec)\n            else:\n                selected.append(rec)\n        else:\n            rejected.append(rec)\n    return {'selected': [r['id'] for r in sort_records(selected)], 'blocked': [r['id'] for r in sort_records(blocked)], 'rejected': [r['id'] for r in sort_records(rejected)]}\n", "policy.py": "POLICY = {\"adjacency_allowed\": False, \"blackout_day\": \"2026-11-02\", \"cancelled_blocks\": False, \"capacity\": 2, \"cutoff_hour\": 18, \"cutoff_inclusive\": False, \"duplicate_policy\": \"last\", \"duration_max\": 90, \"lead_minutes\": 60, \"priority_high_first\": False, \"report_order\": \"input\", \"timezone\": \"UTC\"}\n", "helpers.py": "from datetime import datetime\n\ndef parse_datetime(value):\n    if not isinstance(value, str):\n        return None\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 ValueError:\n        return None\n    if dt.tzinfo is None or dt.utcoffset() is None:\n        return None\n    return dt\n\ndef is_int(value):\n    return isinstance(value, int) and not isinstance(value, bool)\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\ndef make_cutoff(start_local, cutoff_hour, tz):\n    return datetime(start_local.year, start_local.month, start_local.day, int(cutoff_hour), 0, tzinfo=tz)\n"}}