Answer A: Anthropic Claude Fable 5
"""
Dependency-based task scheduler.
Produces an execution plan as a list of batches (lists of task IDs),
where every task in a batch can run concurrently, and batches must run
sequentially. Uses Kahn's algorithm (level-by-level topological sort).
Raises ValueError on:
- duplicate task IDs,
- dependencies that reference unknown task IDs,
- circular dependencies (with the offending tasks listed).
"""
from collections import deque
from typing import Dict, List
class TaskScheduler:
"""Schedules tasks into parallelizable batches based on dependencies."""
def __init__(self, tasks: List[dict]):...
Show Full Answer ▼
"""
Dependency-based task scheduler.
Produces an execution plan as a list of batches (lists of task IDs),
where every task in a batch can run concurrently, and batches must run
sequentially. Uses Kahn's algorithm (level-by-level topological sort).
Raises ValueError on:
- duplicate task IDs,
- dependencies that reference unknown task IDs,
- circular dependencies (with the offending tasks listed).
"""
from collections import deque
from typing import Dict, List
class TaskScheduler:
"""Schedules tasks into parallelizable batches based on dependencies."""
def __init__(self, tasks: List[dict]):
self.tasks = tasks
self._validate_and_build_graph()
def _validate_and_build_graph(self) -> None:
# Collect all task IDs and check for duplicates.
self.task_ids = set()
for task in self.tasks:
if 'id' not in task:
raise ValueError(f"Task is missing required 'id' key: {task!r}")
task_id = task['id']
if task_id in self.task_ids:
raise ValueError(f"Duplicate task ID found: '{task_id}'")
self.task_ids.add(task_id)
# Build adjacency list (dependency -> dependents) and in-degree map.
self.dependents: Dict[str, List[str]] = {tid: [] for tid in self.task_ids}
self.in_degree: Dict[str, int] = {tid: 0 for tid in self.task_ids}
for task in self.tasks:
task_id = task['id']
for dep in task.get('dependencies') or []:
if dep not in self.task_ids:
raise ValueError(
f"Task '{task_id}' depends on unknown task ID '{dep}'"
)
if dep == task_id:
raise ValueError(
f"Task '{task_id}' depends on itself (circular dependency)"
)
self.dependents[dep].append(task_id)
self.in_degree[task_id] += 1
def schedule(self) -> List[List[str]]:
"""
Return the execution plan as a list of batches.
Each batch is a list of task IDs that can be executed concurrently.
Batches must be executed in the returned order.
"""
in_degree = dict(self.in_degree) # work on a copy
current_batch = deque(
tid for tid in in_degree if in_degree[tid] == 0
)
plan: List[List[str]] = []
scheduled_count = 0
while current_batch:
batch = sorted(current_batch) # deterministic output (order is arbitrary)
plan.append(batch)
scheduled_count += len(batch)
next_batch = deque()
for task_id in batch:
for dependent in self.dependents[task_id]:
in_degree[dependent] -= 1
if in_degree[dependent] == 0:
next_batch.append(dependent)
current_batch = next_batch
if scheduled_count != len(self.task_ids):
unresolved = sorted(
tid for tid in in_degree if in_degree[tid] > 0
)
raise ValueError(
"Circular dependency detected involving tasks: "
+ ", ".join(f"'{t}'" for t in unresolved)
)
return plan
def schedule_tasks(tasks: List[dict]) -> List[List[str]]:
"""
Convenience function: schedule a list of task dictionaries.
Args:
tasks: List of dicts, each with keys 'id' (str), optionally 'name'
(str), and 'dependencies' (list of task ID strings).
Returns:
A list of lists of task IDs. Each inner list is a batch of tasks
that can run in parallel; batches run sequentially in order.
Raises:
ValueError: If a dependency refers to a non-existent task ID, if a
circular dependency exists, or if task IDs are duplicated.
"""
return TaskScheduler(tasks).schedule()
if name == 'main':
# Example 1
tasks = [
{'id': 'A', 'name': 'Data Ingestion', 'dependencies': []},
{'id': 'B', 'name': 'Data Cleaning', 'dependencies': ['A']},
{'id': 'C', 'name': 'Feature Engineering', 'dependencies': ['A']},
{'id': 'D', 'name': 'Model Training', 'dependencies': ['B', 'C']},
{'id': 'E', 'name': 'Setup Logging', 'dependencies': []},
{'id': 'F', 'name': 'Model Deployment', 'dependencies': ['D']},
]
print(schedule_tasks(tasks))
# -> [['A', 'E'], ['B', 'C'], ['D'], ['F']]
# Example 2
pipeline = [
{'id': 'checkout', 'dependencies': []},
{'id': 'build', 'dependencies': ['checkout']},
{'id': 'unit_test', 'dependencies': ['build']},
{'id': 'integration_test', 'dependencies': ['build']},
{'id': 'deploy', 'dependencies': ['unit_test', 'integration_test']},
]
print(schedule_tasks(pipeline))
# -> [['checkout'], ['build'], ['integration_test', 'unit_test'], ['deploy']]
# Example 3: circular dependency raises ValueError
cyclic = [
{'id': 'X', 'dependencies': ['Y']},
{'id': 'Y', 'dependencies': ['X']},
]
try:
schedule_tasks(cyclic)
except ValueError as e:
print(f"ValueError: {e}")
# Example 4: unknown dependency raises ValueError
broken = [
{'id': 'A', 'dependencies': ['missing_task']},
]
try:
schedule_tasks(broken)
except ValueError as e:
print(f"ValueError: {e}")
Result
Winning Votes
2 / 3
Average Score
Total Score
Overall Comments
Answer A is functionally correct, using Kahn's algorithm with a clean level-by-level (batch) topological sort. It validates duplicate IDs, unknown dependencies, and self-loops, and detects cycles via the scheduled-count check, raising descriptive ValueErrors that even list the offending tasks. Notable strengths: it builds the graph at construction time (so unknown-dependency errors surface eagerly), produces deterministic output via sorting, includes thorough docstrings, type hints, and a comprehensive set of runnable examples covering both valid and invalid cases (cycle and unknown dependency). It also offers both a class API and a convenience function, matching the prompt's flexibility. Minor weaknesses: sorting each batch is a small (and unrequested) overhead, and the eager self-dependency check is slightly redundant given the cycle detector, but neither is harmful.
View Score Details ▼
Correctness
Weight 35%Correctly implements level-by-level Kahn's algorithm; valid schedules match the expected outputs, cycles and unknown dependencies both raise ValueError, and the cycle check via scheduled_count is sound. Sorted batches guarantee correct, deterministic results.
Completeness
Weight 20%Handles duplicates, unknown deps, self-loops, and cycles; provides both class and function APIs; and includes four runnable examples covering valid schedules plus both error types, demonstrating full coverage.
Code Quality
Weight 20%Clean class structure with clear separation of validation and scheduling, good docstrings, type hints, and informative error messages. Minor redundancy in the explicit self-dependency check.
Practical Value
Weight 15%Deterministic output and eager validation at construction make it dependable and easy to integrate; runnable examples for all paths aid practical adoption.
Instruction Following
Weight 10%Matches required output format, raises ValueError for both required error cases with descriptive messages, and provides a function as requested; fully aligns with the prompt.
Total Score
Overall Comments
Answer A is a strong, mostly correct implementation using level-by-level Kahn's algorithm, and it cleanly returns parallelizable batches. It handles unknown dependencies, duplicate IDs, and cycles with clear errors, and the code is readable and well structured. Its main weakness is that it performs less input validation than Answer B and is slightly less robust for malformed inputs beyond the core prompt requirements.
View Score Details ▼
Correctness
Weight 35%Implements batch-wise topological sorting correctly and detects unknown dependencies and cycles. It also catches self-dependency explicitly. A minor limitation is that malformed dependency field types are not validated and could lead to unintended behavior rather than a clear contract-preserving error.
Completeness
Weight 20%Covers all required behaviors and even adds duplicate-ID handling and examples. However, it is less complete around malformed input validation such as non-list dependencies or non-string IDs beyond missing 'id'.
Code Quality
Weight 20%Well organized with a clear class design, helper method, type hints, docstrings, and deterministic sorted batches. The structure is easy to follow and maintain.
Practical Value
Weight 15%Useful in practice, especially with deterministic batch ordering and descriptive errors. It is somewhat less defensive against malformed inputs, which lowers robustness in production contexts.
Instruction Following
Weight 10%Follows the prompt closely: accepts task dictionaries, returns list-of-lists batches, and raises ValueError for cycles and missing dependencies. The implementation and examples align well with the required answer type.
Total Score
Overall Comments
Answer A provides an excellent, professional-quality solution. It uses a well-structured class-based design that cleanly separates graph building and validation from the scheduling logic. The implementation of Kahn's algorithm is correct and efficient. Error handling is robust, covering all specified cases plus additional ones like duplicate task IDs. The code is clean, well-documented with type hints, and includes a comprehensive `if __name__ == '__main__'` block that serves as a set of mini-tests, demonstrating both successful execution and error handling.
View Score Details ▼
Correctness
Weight 35%The implementation of Kahn's algorithm is flawless. It correctly identifies batches of parallelizable tasks and respects all dependencies, producing the correct output for the given examples.
Completeness
Weight 20%The solution correctly handles all specified requirements, including detection of circular dependencies and non-existent dependencies. It also adds useful checks for duplicate task IDs and self-dependencies.
Code Quality
Weight 20%The code quality is excellent. The class-based design provides great structure and separation of concerns. The code is clean, readable, well-documented, and uses type hints effectively. The `if __name__ == '__main__'` block is comprehensive and demonstrates the code's full functionality.
Practical Value
Weight 15%The solution is highly practical. The class-based design makes it easy to reuse and extend. An instance of the scheduler could be created and its graph inspected or reused, which is a common requirement in real-world applications.
Instruction Following
Weight 10%The answer perfectly follows all instructions, including the input/output format, the choice of a function or class, and the specific error handling requirements.