{
  "name": "long-context-code-review-fix",
  "description": "Find and fix 6 subtle bugs scattered throughout a 150+ line Python file",
  "dataset": "terminal-bench-local",
  "difficulty": "hard",
  "instruction": "The file task_scheduler.py implements a simple task scheduling system. It has 6 subtle bugs scattered throughout the code. The bugs include off-by-one errors, wrong variable references, missing edge case handling, and incorrect logic.\n\nYour job is to carefully read the ENTIRE file, identify ALL 6 bugs, and fix them. Each bug is subtle - not a syntax error, but a logic error that causes incorrect behavior.\n\nHints about the types of bugs (but not their locations):\n- An off-by-one error in an index calculation\n- A variable that references the wrong thing\n- A comparison operator that is wrong\n- A missing edge case that causes a crash\n- An accumulator that doesn't reset properly\n- A sort that uses the wrong key\n\nRun python3 test_scheduler.py to verify all bugs are fixed.",
  "setup_files": {
    "task_scheduler.py": "\"\"\"A simple priority-based task scheduler.\n\nTasks have a name, priority (1=highest, 10=lowest), duration in minutes,\nand optional dependencies on other tasks.\n\"\"\"\n\nfrom collections import defaultdict\nfrom datetime import datetime, timedelta\n\n\nclass Task:\n    \"\"\"Represents a schedulable task.\"\"\"\n    \n    def __init__(self, name, priority, duration, dependencies=None):\n        self.name = name\n        self.priority = priority\n        self.duration = duration\n        self.dependencies = dependencies or []\n        self.completed = False\n        self.start_time = None\n        self.end_time = None\n\n    def __repr__(self):\n        return f\"Task({self.name}, pri={self.priority}, dur={self.duration}m)\"\n\n\nclass TaskScheduler:\n    \"\"\"Schedules and manages tasks.\"\"\"\n    \n    def __init__(self):\n        self.tasks = {}\n        self.execution_order = []\n        self.current_time = datetime(2024, 1, 1, 9, 0)  # Start at 9 AM\n    \n    def add_task(self, name, priority, duration, dependencies=None):\n        \"\"\"Add a task to the scheduler.\n        \n        Args:\n            name: Unique task name.\n            priority: Priority level (1=highest, 10=lowest).\n            duration: Duration in minutes.\n            dependencies: List of task names that must complete first.\n            \n        Returns:\n            The created Task object.\n            \n        Raises:\n            ValueError: If task name already exists or priority is out of range.\n        \"\"\"\n        if name in self.tasks:\n            raise ValueError(f\"Task '{name}' already exists\")\n        if priority < 1 or priority > 10:\n            raise ValueError(f\"Priority must be 1-10, got {priority}\")\n        \n        task = Task(name, priority, duration, dependencies)\n        self.tasks[name] = task\n        return task\n    \n    def get_ready_tasks(self):\n        \"\"\"Get tasks that are ready to run (all dependencies met).\n        \n        Returns:\n            List of Task objects sorted by priority (highest first, i.e., lowest number).\n        \"\"\"\n        ready = []\n        for task in self.tasks.values():\n            if task.completed:\n                continue\n            # Check if all dependencies are completed\n            deps_met = True\n            for dep_name in task.dependencies:\n                dep_task = self.tasks.get(dep_name)\n                if dep_task is None or not dep_task.completed:\n                    deps_met = False\n                    break\n            if deps_met:\n                ready.append(task)\n        \n        # BUG #6: Sort by priority descending (higher number first) instead of ascending\n        # Priority 1 is highest, so we should sort ascending (lowest number first)\n        ready.sort(key=lambda t: -t.priority)\n        return ready\n    \n    def execute_next(self):\n        \"\"\"Execute the highest-priority ready task.\n        \n        Returns:\n            The executed Task, or None if no tasks are ready.\n        \"\"\"\n        ready = self.get_ready_tasks()\n        if not ready:\n            return None\n        \n        task = ready[0]\n        task.start_time = self.current_time\n        task.end_time = self.current_time + timedelta(minutes=task.duration)\n        task.completed = True\n        self.current_time = task.end_time\n        self.execution_order.append(task.name)\n        return task\n    \n    def execute_all(self):\n        \"\"\"Execute all tasks in priority order, respecting dependencies.\n        \n        Returns:\n            List of task names in execution order.\n        \"\"\"\n        while True:\n            task = self.execute_next()\n            if task is None:\n                break\n        return list(self.execution_order)\n    \n    def get_schedule(self):\n        \"\"\"Get the full schedule as a list of dicts.\n        \n        Returns:\n            List of dicts with task info, in execution order.\n        \"\"\"\n        schedule = []\n        for name in self.execution_order:\n            task = self.tasks[name]\n            schedule.append({\n                'name': task.name,\n                'priority': task.priority,\n                'duration': task.duration,\n                'start_time': task.start_time.strftime('%H:%M'),\n                'end_time': task.end_time.strftime('%H:%M'),\n            })\n        return schedule\n    \n    def find_critical_path(self):\n        \"\"\"Find the critical path - longest chain of dependent tasks.\n        \n        Returns:\n            A list of task names representing the critical path,\n            or an empty list if there are no tasks.\n        \"\"\"\n        if not self.tasks:\n            return []\n        \n        # Build dependency graph\n        def get_chain_duration(task_name, visited=None):\n            if visited is None:\n                visited = set()\n            # BUG #4: No check for task_name not existing in self.tasks\n            task = self.tasks[task_name]\n            if task_name in visited:\n                return 0, []\n            visited.add(task_name)\n            \n            if not task.dependencies:\n                return task.duration, [task_name]\n            \n            max_duration = 0\n            max_path = []\n            for dep in task.dependencies:\n                dur, path = get_chain_duration(dep, visited)\n                if dur > max_duration:\n                    max_duration = dur\n                    max_path = path\n            \n            return max_duration + task.duration, max_path + [task_name]\n        \n        best_duration = 0\n        best_path = []\n        for name in self.tasks:\n            dur, path = get_chain_duration(name)\n            if dur > best_duration:\n                best_duration = dur\n                best_path = path\n        \n        return best_path\n    \n    def get_utilization_report(self):\n        \"\"\"Calculate resource utilization stats.\n        \n        Returns:\n            A dict with:\n                - 'total_task_time': sum of all task durations\n                - 'total_elapsed': minutes from first start to last end\n                - 'utilization_pct': percentage of elapsed time spent on tasks\n                - 'idle_time': total idle minutes\n        \"\"\"\n        if not self.execution_order:\n            return {\n                'total_task_time': 0,\n                'total_elapsed': 0,\n                'utilization_pct': 0.0,\n                'idle_time': 0\n            }\n        \n        total_task_time = 0\n        for name in self.execution_order:\n            task = self.tasks[name]\n            # BUG #5: This accumulates across multiple calls because we don't\n            # calculate from scratch - but actually the bug is we're using\n            # task.priority instead of task.duration\n            total_task_time += task.priority\n        \n        first_start = self.tasks[self.execution_order[0]].start_time\n        last_end = self.tasks[self.execution_order[-1]].end_time\n        total_elapsed = (last_end - first_start).total_seconds() / 60\n        \n        if total_elapsed == 0:\n            utilization = 100.0\n        else:\n            utilization = (total_task_time / total_elapsed) * 100\n        \n        return {\n            'total_task_time': total_task_time,\n            'total_elapsed': total_elapsed,\n            'utilization_pct': round(utilization, 1),\n            'idle_time': total_elapsed - total_task_time\n        }\n    \n    def get_task_by_index(self, index):\n        \"\"\"Get a task by its position in execution order.\n        \n        Args:\n            index: 1-based index into the execution order.\n            \n        Returns:\n            The Task object, or None if index is out of range.\n        \"\"\"\n        # BUG #1: Off-by-one error. Index is 1-based but we're not adjusting.\n        # Should be index - 1 to convert from 1-based to 0-based.\n        if index < 1 or index > len(self.execution_order):\n            return None\n        return self.tasks[self.execution_order[index]]\n    \n    def get_dependent_tasks(self, task_name):\n        \"\"\"Find all tasks that depend on the given task (directly or indirectly).\n        \n        Args:\n            task_name: Name of the task to find dependents of.\n            \n        Returns:\n            A set of task names that depend on the given task.\n        \"\"\"\n        dependents = set()\n        \n        def find_dependents(name):\n            for other_name, other_task in self.tasks.items():\n                if name in other_task.dependencies and other_name not in dependents:\n                    dependents.add(other_name)\n                    find_dependents(other_name)\n        \n        find_dependents(task_name)\n        return dependents\n    \n    def reschedule_task(self, task_name, new_priority):\n        \"\"\"Change a task's priority (only if not yet executed).\n        \n        Args:\n            task_name: Name of the task to reschedule.\n            new_priority: New priority value (1-10).\n            \n        Returns:\n            True if rescheduled, False if task is already completed.\n            \n        Raises:\n            ValueError: If task not found or priority out of range.\n        \"\"\"\n        if task_name not in self.tasks:\n            raise ValueError(f\"Task '{task_name}' not found\")\n        if new_priority < 1 or new_priority > 10:\n            raise ValueError(f\"Priority must be 1-10, got {new_priority}\")\n        \n        task = self.tasks[task_name]\n        # BUG #3: Wrong comparison - should check if task IS completed,\n        # but uses 'not completed' which inverts the logic\n        if not task.completed:\n            return False\n        \n        task.priority = new_priority\n        return True\n    \n    def get_tasks_in_priority_range(self, min_pri, max_pri):\n        \"\"\"Get all tasks with priority between min_pri and max_pri (inclusive).\n        \n        Args:\n            min_pri: Minimum priority (1 = highest).\n            max_pri: Maximum priority (10 = lowest).\n            \n        Returns:\n            List of Task objects in priority order.\n        \"\"\"\n        result = []\n        for task in self.tasks.values():\n            # BUG #2: Uses wrong variable - compares task.duration instead of task.priority\n            if task.duration >= min_pri and task.duration <= max_pri:\n                result.append(task)\n        \n        result.sort(key=lambda t: t.priority)\n        return result\n    \n    def reset(self):\n        \"\"\"Reset the scheduler, clearing all tasks and execution history.\"\"\"\n        self.tasks.clear()\n        self.execution_order.clear()\n        self.current_time = datetime(2024, 1, 1, 9, 0)\n",
    "test_scheduler.py": "\"\"\"Verify that all 6 bugs in task_scheduler.py are fixed.\"\"\"\nimport sys\nfrom datetime import datetime, timedelta\n\nerrors = []\n\ntry:\n    from task_scheduler import TaskScheduler, Task\nexcept Exception as e:\n    print(f\"FAIL: Cannot import task_scheduler: {e}\")\n    sys.exit(1)\n\n# === Test 1: get_task_by_index (off-by-one bug) ===\ntry:\n    s = TaskScheduler()\n    s.add_task('A', 1, 30)\n    s.add_task('B', 2, 20)\n    s.execute_all()\n    \n    # Index 1 should return first task 'A'\n    t1 = s.get_task_by_index(1)\n    if t1 is None:\n        errors.append(\"Bug 1 (off-by-one): get_task_by_index(1) returned None\")\n    elif t1.name != 'A':\n        errors.append(f\"Bug 1 (off-by-one): get_task_by_index(1) returned '{t1.name}', expected 'A'\")\n    \n    t2 = s.get_task_by_index(2)\n    if t2 is None:\n        errors.append(\"Bug 1 (off-by-one): get_task_by_index(2) returned None\")\n    elif t2.name != 'B':\n        errors.append(f\"Bug 1 (off-by-one): get_task_by_index(2) returned '{t2.name}', expected 'B'\")\n    \n    # Index 3 should be out of range\n    t3 = s.get_task_by_index(3)\n    if t3 is not None:\n        errors.append(f\"Bug 1 (off-by-one): get_task_by_index(3) should return None, got '{t3.name}'\")\nexcept IndexError as e:\n    errors.append(f\"Bug 1 (off-by-one): get_task_by_index raised IndexError: {e}\")\nexcept Exception as e:\n    errors.append(f\"Bug 1 test error: {type(e).__name__}: {e}\")\n\n# === Test 2: get_tasks_in_priority_range (wrong variable) ===\ntry:\n    s = TaskScheduler()\n    s.add_task('X', 2, 60)  # priority 2, duration 60\n    s.add_task('Y', 5, 10)  # priority 5, duration 10\n    s.add_task('Z', 8, 30)  # priority 8, duration 30\n    \n    result = s.get_tasks_in_priority_range(1, 5)\n    names = [t.name for t in result]\n    if sorted(names) != ['X', 'Y']:\n        errors.append(f\"Bug 2 (wrong variable): priority range 1-5 returned {names}, expected ['X', 'Y']\")\n    \n    result = s.get_tasks_in_priority_range(6, 10)\n    names = [t.name for t in result]\n    if names != ['Z']:\n        errors.append(f\"Bug 2 (wrong variable): priority range 6-10 returned {names}, expected ['Z']\")\nexcept Exception as e:\n    errors.append(f\"Bug 2 test error: {type(e).__name__}: {e}\")\n\n# === Test 3: reschedule_task (wrong comparison) ===\ntry:\n    s = TaskScheduler()\n    s.add_task('M', 3, 20)\n    \n    # Task is not completed, so rescheduling should succeed\n    result = s.reschedule_task('M', 1)\n    if result != True:\n        errors.append(f\"Bug 3 (wrong comparison): reschedule of pending task returned {result}, expected True\")\n    \n    if s.tasks['M'].priority != 1:\n        errors.append(f\"Bug 3 (wrong comparison): priority not updated after reschedule\")\n    \n    # Now complete the task\n    s.execute_all()\n    \n    # Task is completed, rescheduling should return False\n    result = s.reschedule_task('M', 5)\n    if result != False:\n        errors.append(f\"Bug 3 (wrong comparison): reschedule of completed task returned {result}, expected False\")\nexcept Exception as e:\n    errors.append(f\"Bug 3 test error: {type(e).__name__}: {e}\")\n\n# === Test 4: find_critical_path (missing edge case) ===\ntry:\n    s = TaskScheduler()\n    s.add_task('P', 1, 30)\n    s.add_task('Q', 2, 20, dependencies=['P'])\n    s.add_task('R', 3, 40, dependencies=['Q'])\n    # Add a dependency on a task name that doesn't exist in deps list\n    s.add_task('S', 2, 15, dependencies=['P', 'NONEXISTENT'])\n    \n    # Should not crash when encountering NONEXISTENT dependency\n    try:\n        path = s.find_critical_path()\n        # The critical path should be P->Q->R (90 min) since S has an invalid dep\n        # Actually with the fix, NONEXISTENT should be handled gracefully\n    except KeyError:\n        errors.append(\"Bug 4 (missing edge case): find_critical_path crashed on non-existent dependency\")\nexcept Exception as e:\n    errors.append(f\"Bug 4 test error: {type(e).__name__}: {e}\")\n\n# === Test 5: get_utilization_report (wrong accumulator) ===\ntry:\n    s = TaskScheduler()\n    s.add_task('T1', 1, 30)   # priority=1, duration=30\n    s.add_task('T2', 2, 20)   # priority=2, duration=20\n    s.add_task('T3', 3, 10)   # priority=3, duration=10\n    s.execute_all()\n    \n    report = s.get_utilization_report()\n    # total_task_time should be 30+20+10=60, NOT 1+2+3=6\n    if report['total_task_time'] != 60:\n        errors.append(f\"Bug 5 (wrong accumulator): total_task_time is {report['total_task_time']}, expected 60\")\n    \n    if report['total_elapsed'] != 60:\n        errors.append(f\"Bug 5: total_elapsed is {report['total_elapsed']}, expected 60\")\n    \n    if report['utilization_pct'] != 100.0:\n        errors.append(f\"Bug 5: utilization_pct is {report['utilization_pct']}, expected 100.0\")\n    \n    if report['idle_time'] != 0:\n        errors.append(f\"Bug 5: idle_time is {report['idle_time']}, expected 0\")\nexcept Exception as e:\n    errors.append(f\"Bug 5 test error: {type(e).__name__}: {e}\")\n\n# === Test 6: get_ready_tasks sort order (wrong sort key) ===\ntry:\n    s = TaskScheduler()\n    s.add_task('Lo', 8, 10)   # low priority\n    s.add_task('Hi', 1, 10)   # high priority\n    s.add_task('Mid', 5, 10)  # medium priority\n    \n    ready = s.get_ready_tasks()\n    names = [t.name for t in ready]\n    if names != ['Hi', 'Mid', 'Lo']:\n        errors.append(f\"Bug 6 (wrong sort): ready tasks are {names}, expected ['Hi', 'Mid', 'Lo']\")\n    \n    # Execute should pick highest priority first\n    s.execute_next()\n    if s.execution_order != ['Hi']:\n        errors.append(f\"Bug 6 (wrong sort): first executed was {s.execution_order}, expected ['Hi']\")\nexcept Exception as e:\n    errors.append(f\"Bug 6 test error: {type(e).__name__}: {e}\")\n\n# === Integration test: full workflow ===\ntry:\n    s = TaskScheduler()\n    s.add_task('Setup', 1, 15)\n    s.add_task('Build', 2, 30, dependencies=['Setup'])\n    s.add_task('Test', 2, 20, dependencies=['Build'])\n    s.add_task('Docs', 5, 10, dependencies=['Setup'])\n    s.add_task('Deploy', 3, 15, dependencies=['Test', 'Docs'])\n    \n    order = s.execute_all()\n    \n    # Setup must be first\n    if order[0] != 'Setup':\n        errors.append(f\"Integration: first task should be 'Setup', got '{order[0]}'\")\n    \n    # Deploy must be last\n    if order[-1] != 'Deploy':\n        errors.append(f\"Integration: last task should be 'Deploy', got '{order[-1]}'\")\n    \n    # Build must come before Test\n    if order.index('Build') > order.index('Test'):\n        errors.append(\"Integration: Build should come before Test\")\n    \n    schedule = s.get_schedule()\n    if len(schedule) != 5:\n        errors.append(f\"Integration: schedule has {len(schedule)} entries, expected 5\")\n    \n    report = s.get_utilization_report()\n    if report['total_task_time'] != 90:  # 15+30+20+10+15\n        errors.append(f\"Integration: total_task_time is {report['total_task_time']}, expected 90\")\n\nexcept Exception as e:\n    errors.append(f\"Integration test error: {type(e).__name__}: {e}\")\n\n# === Report ===\nif errors:\n    print(f\"FAILED with {len(errors)} error(s):\")\n    for e in errors:\n        print(f\"  - {e}\")\n    sys.exit(1)\nelse:\n    print(\"ALL 6 BUGS FIXED - ALL CHECKS PASSED\")\n    print(\"  - Bug 1: Off-by-one in get_task_by_index fixed\")\n    print(\"  - Bug 2: Wrong variable in get_tasks_in_priority_range fixed\")\n    print(\"  - Bug 3: Wrong comparison in reschedule_task fixed\")\n    print(\"  - Bug 4: Missing edge case in find_critical_path fixed\")\n    print(\"  - Bug 5: Wrong accumulator in get_utilization_report fixed\")\n    print(\"  - Bug 6: Wrong sort order in get_ready_tasks fixed\")\n    print(\"  - Integration test passed\")\n    sys.exit(0)\n"
  },
  "verify": "cd $BENCH_WORK_DIR && python3 test_scheduler.py",
  "timeout": 360000,
  "tags": ["long-context", "debugging", "code-review", "python", "bug-fixing"]
}