MCPcopy Create free account
hub / github.com/AutoForgeAI/autoforge / compute_scheduling_scores

Function compute_scheduling_scores

api/dependency_resolver.py:274–352  ·  view source on GitHub ↗

Compute scheduling scores for all features. Higher scores mean higher priority for scheduling. The algorithm considers: 1. Unblocking potential - Features that unblock more downstream work score higher 2. Depth in graph - Features with no dependencies (roots) are "shovel-ready" 3. U

(features: list[dict])

Source from the content-addressed store, hash-verified

272
273
274def compute_scheduling_scores(features: list[dict]) -> dict[int, float]:
275 """Compute scheduling scores for all features.
276
277 Higher scores mean higher priority for scheduling. The algorithm considers:
278 1. Unblocking potential - Features that unblock more downstream work score higher
279 2. Depth in graph - Features with no dependencies (roots) are "shovel-ready"
280 3. User priority - Existing priority field as tiebreaker
281
282 Score formula: (1000 * unblock) + (100 * depth_score) + (10 * priority_factor)
283
284 Args:
285 features: List of feature dicts with id, priority, dependencies fields
286
287 Returns:
288 Dict mapping feature_id -> score (higher = schedule first)
289 """
290 if not features:
291 return {}
292
293 # Build adjacency lists
294 children: dict[int, list[int]] = {f["id"]: [] for f in features} # who depends on me
295 parents: dict[int, list[int]] = {f["id"]: [] for f in features} # who I depend on
296
297 for f in features:
298 for dep_id in (f.get("dependencies") or []):
299 if dep_id in children: # Only valid deps
300 children[dep_id].append(f["id"])
301 parents[f["id"]].append(dep_id)
302
303 # Calculate depths via BFS from roots
304 # Use visited set to prevent infinite loops from circular dependencies
305 # Use deque for O(1) popleft instead of list.pop(0) which is O(n)
306 depths: dict[int, int] = {}
307 visited: set[int] = set()
308 roots = [f["id"] for f in features if not parents[f["id"]]]
309 bfs_queue: deque[tuple[int, int]] = deque((root, 0) for root in roots)
310 while bfs_queue:
311 node_id, depth = bfs_queue.popleft()
312 if node_id in visited:
313 continue # Skip already visited nodes (handles cycles)
314 visited.add(node_id)
315 depths[node_id] = depth
316 for child_id in children[node_id]:
317 if child_id not in visited:
318 bfs_queue.append((child_id, depth + 1))
319
320 # Handle orphaned nodes (shouldn't happen but be safe)
321 for f in features:
322 if f["id"] not in depths:
323 depths[f["id"]] = 0
324
325 # Calculate transitive downstream counts (reverse topo order)
326 downstream: dict[int, int] = {f["id"]: 0 for f in features}
327 # Process in reverse depth order (leaves first)
328 for fid in sorted(depths.keys(), key=lambda x: -depths[x]):
329 for parent_id in parents[fid]:
330 downstream[parent_id] += 1 + downstream[fid]
331

Calls

no outgoing calls