Orivel Orivel
Open menu

Implement a Dependency Resolver with Semantic Versioning

Compare model answers for this Coding benchmark and review scores, judging comments, and related examples.

Login or register to use likes and favorites. Register

X f L

Contents

Task Overview

Benchmark Genres

Coding

Task Creator Model

Answering Models

Judge Models

Task Prompt

Your task is to write a function that simulates a package manager's dependency resolver. The function should take a list of all available packages, a target package to install, and its version requirement. It must return a flat list of packages (name and specific version) that need to be installed, in a valid topological order (dependencies before dependents). The resolver must handle semantic versioning (SemVer) constraints. For this task, you only need to support exact versions, caret (`^`), and tilde (`~`) spec...

Show more

Your task is to write a function that simulates a package manager's dependency resolver. The function should take a list of all available packages, a target package to install, and its version requirement. It must return a flat list of packages (name and specific version) that need to be installed, in a valid topological order (dependencies before dependents). The resolver must handle semantic versioning (SemVer) constraints. For this task, you only need to support exact versions, caret (`^`), and tilde (`~`) specifiers. - `1.2.3`: Must be exactly version 1.2.3. - `^1.2.3`: Allows versions from 1.2.3 up to, but not including, 2.0.0 (i.e., `>=1.2.3 <2.0.0`). - `~1.2.3`: Allows versions from 1.2.3 up to, but not including, 1.3.0 (i.e., `>=1.2.3 <1.3.0`). Your implementation must: 1. Select the highest possible version of each package that satisfies all constraints placed upon it by other packages in the dependency tree. 2. Produce a topologically sorted list of packages for installation. 3. Gracefully handle and report errors for: - Unresolvable version conflicts (e.g., one dependency requires `^1.0.0` and another requires `^2.0.0` of the same package). - Circular dependencies (e.g., package A depends on B, and B depends on A). - A required package or version not being available. You can choose any programming language for your implementation. Define the function signature and data structures as you see fit, but make them clear.

Task Context

Assume the list of available packages is provided in a structure like the following JSON object. The keys are package names. The values are arrays of available versions, where each version object contains a version string and an object listing its dependencies. An example of this data structure is: {"pkg-A": [{"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}}], "pkg-B": [{"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {...

Show more

Assume the list of available packages is provided in a structure like the following JSON object. The keys are package names. The values are arrays of available versions, where each version object contains a version string and an object listing its dependencies. An example of this data structure is: {"pkg-A": [{"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}}], "pkg-B": [{"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {}}, {"version": "1.1.0", "dependencies": {}}, {"version": "2.0.0", "dependencies": {}}], "pkg-C": [{"version": "1.0.0", "dependencies": {"pkg-A": "^1.0.0", "pkg-B": "^1.0.0"}}], "pkg-D": [{"version": "1.0.0", "dependencies": {"pkg-D": "^1.0.0"}}], "pkg-E": [{"version": "1.0.0", "dependencies": {"pkg-F": "^1.0.0"}}], "pkg-F": [{"version": "1.0.0", "dependencies": {"pkg-E": "^1.0.0"}}]}. For example, if you were asked to resolve `pkg-C` with version requirement `^1.0.0`, a correct output might be a list like `[{"name": "pkg-B", "version": "1.1.0"}, {"name": "pkg-A", "version": "1.1.0"}, {"name": "pkg-C", "version": "1.0.0"}]` (the order of pkg-B and pkg-A can be swapped). This is because `pkg-C@1.0.0` needs `pkg-A@^1.0.0` and `pkg-B@^1.0.0`. The best version for `pkg-A` is `1.1.0`, which in turn needs `pkg-B@^1.1.0`. The intersection of constraints `^1.0.0` and `^1.1.0` for `pkg-B` results in `^1.1.0`, so `pkg-B@1.1.0` is chosen. If asked to resolve `pkg-D` or `pkg-E`, the function should report a circular dependency.

Judging Policy

A high-quality solution must be a correct, robust, and well-written program. - **Correctness:** The primary criterion is correctness. The final list of packages must satisfy all dependency constraints, use the highest valid versions, and be in a correct topological order. The logic for parsing SemVer ranges (`^`, `~`) must be accurate. - **Robustness and Error Handling:** The code must not crash on complex or invalid inputs. It should correctly identify and report clear, understandable error messages for all failur...

Show more

A high-quality solution must be a correct, robust, and well-written program. - **Correctness:** The primary criterion is correctness. The final list of packages must satisfy all dependency constraints, use the highest valid versions, and be in a correct topological order. The logic for parsing SemVer ranges (`^`, `~`) must be accurate. - **Robustness and Error Handling:** The code must not crash on complex or invalid inputs. It should correctly identify and report clear, understandable error messages for all failure cases, including version conflicts, circular dependencies, and missing packages/versions. - **Code Quality and Design:** The solution should be well-structured and readable. Logic should be separated into manageable functions (e.g., for version parsing, graph building, and resolution). The choice of algorithms and data structures should be appropriate for the problem's complexity. - **Completeness:** The solution should be a complete, runnable function or program that demonstrates how to use it with the example data.

Answers

""" Dependency resolver with SemVer support (exact, ^, ~). Implements backtracking to select the highest possible version per package consistent with all constraints, detects circular deps, missing packages/versions, and conflicts. API: resolve_dependencies(available_packages, target_name, target_spec) - available_packages: dict mapping package name -> list of versions, where each version is a dict {"version": "1.2.3", "dependencies": {"pkg-B": "^1.0.0", ...}} - target_name: package name string - target_spec: version spec string (exact like "1.2.3", or "^1.2.3", or "~1.2.3") Returns: list...

Show Full Answer

""" Dependency resolver with SemVer support (exact, ^, ~). Implements backtracking to select the highest possible version per package consistent with all constraints, detects circular deps, missing packages/versions, and conflicts. API: resolve_dependencies(available_packages, target_name, target_spec) - available_packages: dict mapping package name -> list of versions, where each version is a dict {"version": "1.2.3", "dependencies": {"pkg-B": "^1.0.0", ...}} - target_name: package name string - target_spec: version spec string (exact like "1.2.3", or "^1.2.3", or "~1.2.3") Returns: list of {"name": pkg, "version": ver} in topological order (dependencies before dependents) Raises exceptions: NotFoundError, ConflictError, CircularDependencyError with descriptive messages. Example usage with the sample data in the prompt is provided at the bottom under `if __name__ == '__main__'`. """ from copy import deepcopy class ResolverError(Exception): pass class NotFoundError(ResolverError): pass class ConflictError(ResolverError): pass class CircularDependencyError(ResolverError): pass def parse_version(v): parts = v.split('.') if len(parts) != 3: raise ValueError(f"Unsupported version format: {v}") try: return tuple(int(p) for p in parts) except Exception: raise ValueError(f"Unsupported version number in: {v}") def cmp_version(a, b): return (a > b) - (a < b) def satisfies_spec(version_str, spec): v = parse_version(version_str) if spec.startswith('^'): base = parse_version(spec[1:]) # ^1.2.3 => >=1.2.3 <2.0.0 min_v = base max_v = (base[0] + 1, 0, 0) return v >= min_v and v < max_v elif spec.startswith('~'): base = parse_version(spec[1:]) # ~1.2.3 => >=1.2.3 <1.3.0 min_v = base max_v = (base[0], base[1] + 1, 0) return v >= min_v and v < max_v else: # exact base = parse_version(spec) return v == base def filter_versions(available_version_list, specs): # available_version_list: list of version strings (e.g. ["1.1.0","1.0.5"]) or list of version dicts # specs: list of spec strings # Return list of version dicts that satisfy all specs result = [] for verobj in available_version_list: ver_str = verobj['version'] ok = True for s in specs: if not satisfies_spec(ver_str, s): ok = False break if ok: result.append(verobj) # sort descending highest first result.sort(key=lambda vd: parse_version(vd['version']), reverse=True) return result def build_versions_index(available_packages): # Normalize and sort available versions descending idx = {} for pkg, versions in available_packages.items(): # ensure each item has 'version' and 'dependencies' vlist = [] for v in versions: deps = v.get('dependencies', {}) if isinstance(v, dict) else {} vlist.append({'version': v['version'], 'dependencies': deps}) vlist.sort(key=lambda vd: parse_version(vd['version']), reverse=True) idx[pkg] = vlist return idx def resolve_dependencies(available_packages, target_name, target_spec): """ Main resolver function. Returns list of {"name": pkg, "version": ver} in topological order. Raises NotFoundError, ConflictError, CircularDependencyError. """ versions_idx = build_versions_index(available_packages) # Ensure target package exists if target_name not in versions_idx: raise NotFoundError(f"Package '{target_name}' not found in available packages") # constraints: package -> list of spec strings that must all be satisfied initial_constraints = {target_name: [target_spec]} chosen = {} # package -> chosen version string # recursion stack for cycle detection stack = [] def resolve_pkg(pkg_name, constraints, chosen, stack): if pkg_name in stack: cycle = stack[stack.index(pkg_name):] + [pkg_name] raise CircularDependencyError(f"Circular dependency detected: {' -> '.join(cycle)}") if pkg_name not in versions_idx: raise NotFoundError(f"Package '{pkg_name}' required but not found") # If already chosen, check it satisfies all current constraints specs = constraints.get(pkg_name, []) if pkg_name in chosen: chosen_ver = chosen[pkg_name] for s in specs: if not satisfies_spec(chosen_ver, s): raise ConflictError(f"Chosen version {pkg_name}@{chosen_ver} does not satisfy new constraint '{s}'") # already resolved and satisfies constraints return # Get candidate versions for this package by filtering available by all specs candidates = filter_versions(versions_idx[pkg_name], specs) if not candidates: # no available version satisfies constraints raise NotFoundError(f"No available version for package '{pkg_name}' satisfies constraints: {specs}") # Try candidates in descending order (highest first) stack.append(pkg_name) last_error = None for cand in candidates: cand_ver = cand['version'] # pick this candidate and try to resolve its dependencies chosen[pkg_name] = cand_ver # prepare new constraints for dependencies new_constraints = deepcopy(constraints) # add dependency constraints deps = cand.get('dependencies', {}) or {} failed = False try: for dep_name, dep_spec in deps.items(): # append dep_spec to new_constraints[dep_name] new_constraints.setdefault(dep_name, []) new_constraints[dep_name].append(dep_spec) # resolve dependency resolve_pkg(dep_name, new_constraints, chosen, stack) # all dependencies resolved for this candidate stack.pop() return except ResolverError as e: # record the error and try next candidate last_error = e failed = True # cleanup chosen for this pkg and continue if pkg_name in chosen: del chosen[pkg_name] # continue to next candidate continue # exhausted candidates if stack: stack.pop() if last_error: # propagate the most recent error (could be Conflict/NotFound/Circular) raise ConflictError(f"Unable to resolve '{pkg_name}': tried versions {[c['version'] for c in candidates]}. Last error: {last_error}") else: raise ConflictError(f"Unable to resolve '{pkg_name}' due to unknown conflict") # Start resolution resolve_pkg(target_name, initial_constraints, chosen, stack) # At this point chosen contains all packages and their selected versions # Build dependency graph for topological sort graph = {pkg: set() for pkg in chosen.keys()} # pkg -> set of dependency package names for pkg, ver in chosen.items(): # find the version object in versions_idx ver_objs = [v for v in versions_idx[pkg] if v['version'] == ver] if not ver_objs: raise NotFoundError(f"Selected version {pkg}@{ver} not found in available list") deps = ver_objs[0].get('dependencies', {}) or {} for d in deps.keys(): if d in chosen: # only include edges for packages in the final chosen set graph[pkg].add(d) # topological sort (dependencies before dependents) - Kahn's algorithm # reverse edges: want order where deps come first, so edges from node -> its deps # We'll invert to compute in-degree where edge dep <- pkg indegree = {pkg: 0 for pkg in graph} for pkg, deps in graph.items(): for d in deps: indegree[d] += 1 # nodes with indegree 0 are leaves (no other package depending on them), but we want dependencies first - # Because our edge direction is pkg -> deps, nodes with indegree 0 are packages that nobody depends on -> can be installed last. # To obtain dependencies before dependents, we should output in reversed topological order of this graph. # Simpler: perform DFS postorder to ensure deps before dependents. visited = set() order = [] def dfs_topo(n): if n in visited: return visited.add(n) for dep in graph.get(n, []): dfs_topo(dep) order.append(n) for node in graph.keys(): dfs_topo(node) # order now has dependencies before dependents result = [] for pkg in order: result.append({'name': pkg, 'version': chosen[pkg]}) # It's possible that some packages were required but had no edges in graph; dfs_topo covers all keys return result # Example usage and simple tests if __name__ == '__main__': sample = { "pkg-A": [ {"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}} ], "pkg-B": [ {"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {}}, {"version": "1.1.0", "dependencies": {}}, {"version": "2.0.0", "dependencies": {}} ], "pkg-C": [ {"version": "1.0.0", "dependencies": {"pkg-A": "^1.0.0", "pkg-B": "^1.0.0"}} ], "pkg-D": [ {"version": "1.0.0", "dependencies": {"pkg-D": "^1.0.0"}} ], "pkg-E": [ {"version": "1.0.0", "dependencies": {"pkg-F": "^1.0.0"}} ], "pkg-F": [ {"version": "1.0.0", "dependencies": {"pkg-E": "^1.0.0"}} ] } # Example 1: resolve pkg-C ^1.0.0 try: res = resolve_dependencies(sample, 'pkg-C', '^1.0.0') print('Resolved pkg-C:^1.0.0 ->', res) except ResolverError as e: print('Error resolving pkg-C:', e) # Example 2: circular self-dependency pkg-D try: res = resolve_dependencies(sample, 'pkg-D', '^1.0.0') print('Resolved pkg-D:^1.0.0 ->', res) except ResolverError as e: print('Error resolving pkg-D:', e) # Example 3: mutual cycle pkg-E -> pkg-F -> pkg-E try: res = resolve_dependencies(sample, 'pkg-E', '^1.0.0') print('Resolved pkg-E:^1.0.0 ->', res) except ResolverError as e: print('Error resolving pkg-E:', e) # Example 4: missing package try: res = resolve_dependencies(sample, 'pkg-Unknown', '^1.0.0') print('Resolved pkg-Unknown:^1.0.0 ->', res) except ResolverError as e: print('Error resolving pkg-Unknown:', e) # Example 5: conflict example - create conflict where two dependents require incompatible versions conflict_sample = deepcopy(sample) conflict_sample['pkg-X'] = [ {"version": "1.0.0", "dependencies": {"pkg-B": "^1.0.0"}}, {"version": "2.0.0", "dependencies": {"pkg-B": "^2.0.0"}} ] conflict_sample['pkg-Y'] = [ {"version": "1.0.0", "dependencies": {"pkg-B": "^1.0.0", "pkg-X": "1.0.0"}} ] try: # Request X@2.0.0 and Y@1.0.0 indirectly may conflict on pkg-B res = resolve_dependencies(conflict_sample, 'pkg-Y', '^1.0.0') print('Resolved conflict sample ->', res) except ResolverError as e: print('Error resolving conflict sample:', e) # You can integrate this module into another system by importing resolve_dependencies.

Result

#1 | Winner

Winning Votes

3 / 3

Average Score

79

Total Score

88

Overall Comments

Answer A provides a robust and correct solution using a backtracking recursive algorithm. This approach is well-suited for this type of constraint satisfaction problem, as it can explore different version choices to find a globally consistent resolution. The code is well-structured, with clear separation of concerns for version parsing, filtering, and the main resolution logic. It correctly implements topological sorting and features excellent error handling with specific, custom exception classes. Crucially, it is also very complete, providing a suite of test cases in the main block that demonstrate its correctness and its ability to handle all the required error scenarios (conflicts, circular dependencies, missing packages).

View Score Details

Correctness

Weight 35%
90

The backtracking algorithm is fundamentally correct for this problem. It correctly explores the solution space to find the highest versions that satisfy all constraints from across the entire dependency tree. The SemVer logic and topological sort are also implemented correctly.

Completeness

Weight 20%
90

The solution is very complete. It provides a runnable `if __name__ == '__main__'` block with a comprehensive set of examples that test the main success case, two types of circular dependencies, missing packages, and a version conflict scenario. This thoroughly demonstrates the solution's capabilities.

Code Quality

Weight 20%
80

The code is well-structured with clear helper functions and good separation of concerns. The use of custom exception classes for error handling is a strong design choice. The code is readable and reasonably commented.

Practical Value

Weight 15%
85

The solution is a correct and robust implementation of a real-world problem. The code is well-designed enough to be adapted for practical use in a larger system.

Instruction Following

Weight 10%
100

The answer perfectly follows all instructions. It correctly implements SemVer constraints, selects the highest valid versions, produces a topologically sorted list, and gracefully handles all specified error conditions with clear messages.

Total Score

72

Overall Comments

Answer A provides a comprehensive and largely correct implementation of the dependency resolver. It uses backtracking to try different candidate versions when conflicts arise, which is a more robust approach. The code handles all three error cases (circular dependencies, version conflicts, missing packages) with custom exception classes. The SemVer parsing for caret and tilde is correct. The topological sort using DFS postorder is correct. The solution includes extensive example usage demonstrating all error cases. However, there's a subtle issue with the backtracking: when backtracking from a failed candidate, it doesn't properly clean up the chosen versions of dependencies that were resolved during that attempt, which could lead to incorrect results in complex scenarios. Despite this, for the given examples, it produces correct output. The code is well-documented with a clear docstring and comments.

View Score Details

Correctness

Weight 35%
70

Answer A correctly implements SemVer parsing for exact, caret, and tilde constraints. It uses backtracking to try alternative versions when resolution fails, which is important for correctness. The topological sort via DFS postorder is correct. However, the backtracking has a flaw: when rolling back a failed candidate, it doesn't clean up chosen versions of already-resolved dependencies, which could cause issues in complex scenarios. For the given examples, it produces correct results.

Completeness

Weight 20%
80

Answer A demonstrates all required error cases: circular self-dependency (pkg-D), mutual circular dependency (pkg-E/pkg-F), missing package, version conflicts, and the main resolution example. It includes 5 test cases covering different scenarios. Custom exception hierarchy provides clear error categorization.

Code Quality

Weight 20%
65

Answer A has good documentation with a module-level docstring and inline comments. Functions are reasonably well-separated. However, the use of deepcopy for constraints on each recursive call is somewhat inefficient, and the backtracking logic with nested try/except could be cleaner. The code is readable but somewhat verbose.

Practical Value

Weight 15%
70

Answer A's backtracking approach makes it more practically useful as a real dependency resolver. The custom exception hierarchy allows callers to handle different error types appropriately. The comprehensive examples serve as good documentation for users. However, the backtracking doesn't fully clean up state, which limits reliability in complex real-world scenarios.

Instruction Following

Weight 10%
80

Answer A follows all instructions: it implements the three SemVer specifiers, selects highest possible versions, produces topologically sorted output, and handles all three error cases (conflicts, circular deps, missing packages). It demonstrates usage with the provided example data and shows expected output.

Judge Models OpenAI GPT-5.4

Total Score

76

Overall Comments

Answer A is a substantial and mostly complete implementation. It supports exact, caret, and tilde SemVer checks, attempts highest-version selection with backtracking, detects cycles, and returns a dependency-first installation order. It also includes custom error types and runnable examples. Its main weakness is correctness under evolving shared constraints: once a dependency is chosen, later-added constraints are not fully propagated back through that package's already-resolved transitive dependencies, and some errors are rewrapped in a way that can blur precise reporting.

View Score Details

Correctness

Weight 35%
71

SemVer matching for exact, caret, and tilde is correct for the prompt's stated scope, and the resolver usually picks highest satisfying versions with dependency-first ordering. However, the algorithm is not fully sound when a package is resolved before all later constraints on its transitive dependencies are known, so some global constraint interactions may be mishandled.

Completeness

Weight 20%
83

It provides a complete runnable program, defines data structures and exceptions, handles missing packages, missing versions, conflicts, and cycles, and includes multiple example cases. The only meaningful gap is that some error categories get collapsed into broader conflict messages during backtracking.

Code Quality

Weight 20%
74

The code is modular, readable, and reasonably organized into parsing, filtering, indexing, resolution, and ordering steps. Some implementation choices are heavy or brittle, such as frequent deep copies and broad exception wrapping that obscures exact failure causes.

Practical Value

Weight 15%
76

This answer is practical enough to run and adapt, and its examples cover successful resolution, missing packages, and cycles. The custom exceptions and straightforward data model make it useful despite edge-case correctness limitations.

Instruction Following

Weight 10%
86

It follows the prompt closely by implementing the resolver, supporting the required SemVer syntax, returning dependency-first output, handling requested error cases, and demonstrating usage with the sample-style data. Minor issues remain in precise error propagation and the exact flat output schema is implemented but via exceptions rather than returned error objects.

from typing import Dict, List, Set, Tuple, Optional from dataclasses import dataclass import re @dataclass class Package: name: str version: str @dataclass class ResolutionResult: success: bool packages: List[Package] error: Optional[str] = None def parse_version(version_str: str) -> Tuple[int, int, int]: """Parse semantic version string to tuple of integers.""" match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', version_str) if not match: raise ValueError(f"Invalid version format: {version_str}") return tuple(map(int, match.groups())) def version_satisfies(version: str, con...

Show Full Answer

from typing import Dict, List, Set, Tuple, Optional from dataclasses import dataclass import re @dataclass class Package: name: str version: str @dataclass class ResolutionResult: success: bool packages: List[Package] error: Optional[str] = None def parse_version(version_str: str) -> Tuple[int, int, int]: """Parse semantic version string to tuple of integers.""" match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', version_str) if not match: raise ValueError(f"Invalid version format: {version_str}") return tuple(map(int, match.groups())) def version_satisfies(version: str, constraint: str) -> bool: """Check if a version satisfies a constraint.""" v = parse_version(version) if constraint.startswith('^'): spec = constraint[1:] spec_v = parse_version(spec) major = spec_v[0] return v >= spec_v and v[0] == major elif constraint.startswith('~'): spec = constraint[1:] spec_v = parse_version(spec) major, minor = spec_v[0], spec_v[1] return v >= spec_v and v[0] == major and v[1] == minor else: spec_v = parse_version(constraint) return v == spec_v def find_best_version(package_name: str, constraint: str, available_packages: Dict) -> Optional[str]: """Find the highest version that satisfies the constraint.""" if package_name not in available_packages: return None versions = [pkg['version'] for pkg in available_packages[package_name]] matching = [v for v in versions if version_satisfies(v, constraint)] if not matching: return None return max(matching, key=parse_version) def resolve_dependencies(available_packages: Dict, target_package: str, version_constraint: str) -> ResolutionResult: """Resolve dependencies for a package with semantic versioning support.""" # Check if target package exists if target_package not in available_packages: return ResolutionResult(False, [], f"Package '{target_package}' not found") # Find best version for target best_version = find_best_version(target_package, version_constraint, available_packages) if best_version is None: return ResolutionResult(False, [], f"No version of '{target_package}' satisfies '{version_constraint}'") # Track resolved packages and constraints resolved: Dict[str, str] = {} # package_name -> version constraints: Dict[str, Set[str]] = {} # package_name -> set of constraints visiting: Set[str] = set() # For cycle detection visited: Set[str] = set() def get_package_info(name: str, version: str) -> Optional[Dict]: """Get package info for a specific version.""" if name not in available_packages: return None for pkg in available_packages[name]: if pkg['version'] == version: return pkg return None def dfs(package_name: str, constraint: str) -> bool: """DFS to resolve dependencies. Returns True if successful.""" # Check for circular dependency if package_name in visiting: return False if package_name in visited: # Already resolved, check if current constraint is satisfied if package_name in resolved: if not version_satisfies(resolved[package_name], constraint): return False return True visiting.add(package_name) # Track constraint if package_name not in constraints: constraints[package_name] = set() constraints[package_name].add(constraint) # Find best version satisfying all constraints all_constraints = constraints[package_name] best_version = None if package_name not in available_packages: visiting.remove(package_name) return False versions = [pkg['version'] for pkg in available_packages[package_name]] for v in sorted(versions, key=parse_version, reverse=True): if all(version_satisfies(v, c) for c in all_constraints): best_version = v break if best_version is None: visiting.remove(package_name) return False resolved[package_name] = best_version # Get dependencies pkg_info = get_package_info(package_name, best_version) if pkg_info is None: visiting.remove(package_name) return False dependencies = pkg_info.get('dependencies', {}) # Resolve dependencies for dep_name, dep_constraint in dependencies.items(): if not dfs(dep_name, dep_constraint): visiting.remove(package_name) return False visiting.remove(package_name) visited.add(package_name) return True # Start resolution if not dfs(target_package, version_constraint): if target_package in visiting: return ResolutionResult(False, [], f"Circular dependency detected involving '{target_package}'") return ResolutionResult(False, [], f"Unable to resolve dependencies for '{target_package}@{version_constraint}'") # Topological sort def topological_sort() -> List[Package]: in_degree = {pkg: 0 for pkg in resolved} graph = {pkg: [] for pkg in resolved} for pkg_name, version in resolved.items(): pkg_info = get_package_info(pkg_name, version) if pkg_info: for dep_name in pkg_info.get('dependencies', {}): if dep_name in resolved: graph[dep_name].append(pkg_name) in_degree[pkg_name] += 1 queue = [pkg for pkg in resolved if in_degree[pkg] == 0] result = [] while queue: pkg = queue.pop(0) result.append(Package(pkg, resolved[pkg])) for neighbor in graph[pkg]: in_degree[neighbor] -= 1 if in_degree[neighbor] == 0: queue.append(neighbor) return result sorted_packages = topological_sort() return ResolutionResult(True, sorted_packages) # Example usage if __name__ == "__main__": packages = { "pkg-A": [ {"version": "1.0.0", "dependencies": {"pkg-B": "~1.0.0"}}, {"version": "1.1.0", "dependencies": {"pkg-B": "^1.1.0"}} ], "pkg-B": [ {"version": "1.0.0", "dependencies": {}}, {"version": "1.0.5", "dependencies": {}}, {"version": "1.1.0", "dependencies": {}}, {"version": "2.0.0", "dependencies": {}} ], "pkg-C": [ {"version": "1.0.0", "dependencies": {"pkg-A": "^1.0.0", "pkg-B": "^1.0.0"}} ], "pkg-D": [ {"version": "1.0.0", "dependencies": {"pkg-D": "^1.0.0"}} ], "pkg-E": [ {"version": "1.0.0", "dependencies": {"pkg-F": "^1.0.0"}} ], "pkg-F": [ {"version": "1.0.0", "dependencies": {"pkg-E": "^1.0.0"}} ] } result = resolve_dependencies(packages, "pkg-C", "^1.0.0") print(f"Success: {result.success}") print(f"Packages: {[(p.name, p.version) for p in result.packages]}") if result.error: print(f"Error: {result.error}")

Result

#2

Winning Votes

0 / 3

Average Score

56

Total Score

51

Overall Comments

Answer B attempts to solve the problem with a simpler, greedy DFS algorithm. While the code is clean and uses modern Python features like type hints and dataclasses, its core logic is flawed. The greedy approach resolves each package once and does not backtrack if a later dependency introduces a conflicting constraint. This means it can fail to find a valid resolution even when one exists, making it incorrect for the general case. The error handling is less robust, returning a simple string in a result object rather than raising specific exceptions. Furthermore, the provided example usage is minimal, only testing the primary success case and failing to demonstrate its handling of the required error conditions.

View Score Details

Correctness

Weight 35%
40

The greedy DFS algorithm is fundamentally flawed. It cannot backtrack to revise an earlier version choice when a new, conflicting constraint is discovered later in the traversal. This means it will incorrectly fail to resolve dependency graphs that have a valid solution, making it unreliable.

Completeness

Weight 20%
50

The solution is incomplete in its demonstration. The example usage only covers the single success case provided in the prompt. It fails to include examples for the required error handling scenarios like circular dependencies or version conflicts, making it difficult to verify its robustness.

Code Quality

Weight 20%
75

The code is clean, readable, and makes good use of modern Python features like type hints and dataclasses. However, the algorithmic design is not appropriate for the problem, and returning an error string in a result object is a less robust error handling pattern than using exceptions.

Practical Value

Weight 15%
40

The solution's practical value is very low because its core algorithm is incorrect. A dependency resolver that cannot be trusted to find a valid resolution is not useful in practice.

Instruction Following

Weight 10%
60

The answer fails to correctly follow the crucial instruction to 'Select the highest possible version of each package that satisfies all constraints placed upon it'. Its greedy algorithm does not guarantee this. It also falls short on demonstrating the required error handling.

Total Score

60

Overall Comments

Answer B provides a cleaner implementation using dataclasses and type hints, which improves readability. However, it has a significant correctness issue with the caret constraint: `^1.2.3` is implemented as checking `v[0] == major`, which means it would accept versions like (1, 0, 0) which is less than 1.2.3 - wait, no, it also checks `v >= spec_v`, so that's actually correct. But there's a more fundamental problem: the DFS-based resolution doesn't handle constraint accumulation properly. When a package is already in `visited` and a new constraint comes in, it checks if the resolved version satisfies the new constraint but doesn't re-resolve if it doesn't - it just returns False. More critically, the circular dependency detection has issues: for pkg-D (self-dependency), when dfs('pkg-D', '^1.0.0') is called, it adds pkg-D to visiting, resolves it, then tries to resolve its dependency on itself - at which point pkg-D is in visiting, so it returns False. This correctly detects the cycle but the error message may not be specific since by the time the outer function checks, visiting might be empty. The code also doesn't implement backtracking - if a chosen version's dependencies fail, it doesn't try alternative versions. This is a significant limitation for correctness.

View Score Details

Correctness

Weight 35%
55

Answer B correctly implements SemVer parsing. However, it lacks backtracking - once the highest version is selected and its dependencies fail, it doesn't try lower versions. This means it would fail to resolve cases where a lower version of a package would work. The constraint accumulation approach has issues: constraints are accumulated globally but if resolution fails partway through, accumulated constraints aren't cleaned up. The circular dependency detection works but error reporting is generic.

Completeness

Weight 20%
60

Answer B only demonstrates the main resolution example (pkg-C) in its main block. While the code handles circular dependencies and missing packages, it doesn't demonstrate these cases. The error messages are less specific - a generic message is returned when resolution fails rather than distinguishing between conflict types.

Code Quality

Weight 20%
70

Answer B uses type hints, dataclasses, and a clean ResolutionResult return type, which improves code quality and readability. The separation of concerns is good with clear helper functions. The DFS resolution function is more concise. However, the lack of custom exceptions and the use of a boolean return for error handling loses information about what went wrong.

Practical Value

Weight 15%
55

Answer B's lack of backtracking significantly limits its practical value - many real-world dependency graphs require trying alternative versions. The ResolutionResult pattern is nice for API design, but the generic error messages make debugging difficult. It would fail on many practical dependency resolution scenarios that require exploring alternative version choices.

Instruction Following

Weight 10%
65

Answer B follows most instructions but falls short on selecting the highest possible version that satisfies all constraints (due to lack of backtracking). It handles the three error cases but with less specificity. The demonstration only shows the happy path case, not the error cases that were specifically requested in the task.

Judge Models OpenAI GPT-5.4

Total Score

58

Overall Comments

Answer B is cleaner and simpler, but it is materially weaker as a dependency resolver. It supports the basic SemVer forms and returns a topological order, but its resolution strategy is not robust enough for shared dependency constraints and does not properly revisit prior choices when new constraints arise. Error reporting is vague, cycle detection is shallow, and it can leave stale constraint state during failed branches. The example usage is minimal and the returned shape differs from the flat name/version object list requested.

View Score Details

Correctness

Weight 35%
48

Basic version parsing and direct constraint checks work, and topological sorting is implemented. But the resolver does not properly backtrack or recompute earlier decisions when new constraints appear, so shared dependency conflicts and globally optimal choices are not handled reliably.

Completeness

Weight 20%
63

It is runnable and includes example usage, SemVer support, topological sorting, and a result wrapper. However, the examples are limited, error categories are not clearly distinguished, and the output type is less aligned with the requested flat list of name/version objects.

Code Quality

Weight 20%
69

The code is concise and readable, with type hints, dataclasses, and helper functions. Still, the design is too simplistic for the problem complexity, and mutable global-like DFS state for constraints and visitation makes failure handling and correctness fragile.

Practical Value

Weight 15%
58

The answer has some practical utility for simple trees, and the typed result object is convenient. In realistic dependency scenarios with intersecting constraints or conflicts, its behavior is too unreliable to trust as a package resolver.

Instruction Following

Weight 10%
64

It follows the high-level instruction to implement a resolver with SemVer support and provide usage examples. However, it is less faithful to the requested behavior around robust conflict handling and returns a custom ResolutionResult with Package dataclasses instead of the plainly requested flat list structure on success.

Comparison Summary

Final rank order is determined by judge-wise rank aggregation (average rank + Borda tie-break). Average score is shown for reference.

Judges: 3

Winning Votes

3 / 3

Average Score

79
View this answer

Winning Votes

0 / 3

Average Score

56
View this answer

Judging Results

Judge Models OpenAI GPT-5.4

Why This Side Won

Answer A wins because it is far closer to a full package-manager-style resolver. It includes backtracking, clearer structure for failure modes, stronger demonstrations, and a dependency-first output. While not perfect, it addresses the core task more completely and robustly than Answer B, whose DFS approach does not reliably resolve combined constraints across the tree and provides weaker conflict and cycle handling.

Why This Side Won

Answer A wins primarily on correctness and robustness. It implements backtracking to try alternative versions when dependency resolution fails for a particular candidate, which is crucial for a correct dependency resolver. Answer B lacks backtracking entirely - once it picks the highest version, if that version's dependencies can't be resolved, it simply fails rather than trying a lower version. Answer A also provides more specific and descriptive error messages through custom exception classes, and includes more comprehensive test cases demonstrating all error scenarios. While Answer B has slightly cleaner code structure with type hints and dataclasses, the correctness advantages of Answer A are more important for this task.

Why This Side Won

Answer A is the winner due to the fundamental correctness of its algorithm. Dependency resolution is a complex constraint satisfaction problem that often requires backtracking, which Answer A correctly implements. Answer B's greedy DFS approach is flawed and will fail in many real-world scenarios. Additionally, Answer A is far more complete, providing comprehensive test cases that demonstrate its robustness across all required success and failure modes, whereas Answer B only tests a single happy path.

X f L