""" Resolution strategies for multi-space artifact lookup. Implements FR-3.1: Deterministic resolution order """ from abc import ABC, abstractmethod from typing import List, Optional from dataclasses import dataclass, field @dataclass class ResolutionConfig: """ Configuration for resolution strategy. Implements FR-3.1: Resolution order configuration Resolution order: 1. Local InformationSpace 2. Explicitly included InformationSpaces 3. Default InformationSpace 4. Team/Shared InformationSpace (if configured) Attributes: space_id: Primary space ID included_spaces: Explicitly included space IDs (ordered) default_space_id: Default space for common artifacts shared_space_id: Team/shared space (optional) max_generation_depth: Maximum nesting depth for generators """ space_id: str included_spaces: List[str] = field(default_factory=list) default_space_id: Optional[str] = None shared_space_id: Optional[str] = None max_generation_depth: int = 3 def to_dict(self) -> dict: """Convert to dictionary for serialization.""" return { "space_id": self.space_id, "included_spaces": self.included_spaces, "default_space_id": self.default_space_id, "shared_space_id": self.shared_space_id, "max_generation_depth": self.max_generation_depth, } @classmethod def from_dict(cls, data: dict) -> "ResolutionConfig": """Create from dictionary.""" return cls( space_id=data["space_id"], included_spaces=data.get("included_spaces", []), default_space_id=data.get("default_space_id"), shared_space_id=data.get("shared_space_id"), max_generation_depth=data.get("max_generation_depth", 3), ) class ResolutionStrategy(ABC): """ Abstract base class for resolution strategies. Defines how to search for artifacts across multiple spaces. """ @abstractmethod def get_search_order(self, config: ResolutionConfig) -> List[str]: """ Get ordered list of space IDs to search. Args: config: Resolution configuration Returns: Ordered list of space IDs (no duplicates) """ pass class MultiSpaceResolutionStrategy(ResolutionStrategy): """ Multi-space resolution strategy with deterministic search order. Implements FR-3.1: Resolution order 1. Local space 2. Included spaces (in order) 3. Default space 4. Shared space """ def get_search_order(self, config: ResolutionConfig) -> List[str]: """ Get deterministic search order. Implements FR-3.1 resolution order: 1. Local InformationSpace (config.space_id) 2. Explicitly included InformationSpaces (config.included_spaces) 3. Default InformationSpace (config.default_space_id) 4. Team/Shared InformationSpace (config.shared_space_id) Removes duplicates while preserving order. Args: config: Resolution configuration Returns: Ordered list of unique space IDs """ search_order = [] seen = set() def add_if_not_seen(space_id: Optional[str]) -> None: """Add space ID if not None and not already seen.""" if space_id and space_id not in seen: search_order.append(space_id) seen.add(space_id) # 1. Local space (highest priority) add_if_not_seen(config.space_id) # 2. Included spaces (in order) for included_id in config.included_spaces: add_if_not_seen(included_id) # 3. Default space add_if_not_seen(config.default_space_id) # 4. Shared space (lowest priority) add_if_not_seen(config.shared_space_id) return search_order class SingleSpaceResolutionStrategy(ResolutionStrategy): """ Simple strategy that only searches the local space. Useful for isolated execution or testing. """ def get_search_order(self, config: ResolutionConfig) -> List[str]: """ Return only the local space. Args: config: Resolution configuration Returns: List containing only the local space ID """ return [config.space_id]