package context import ( "context" "fmt" "time" "chorus.services/bzzz/pkg/ucxl" "chorus.services/bzzz/pkg/config" ) // ContextResolver defines the interface for hierarchical context resolution // // The resolver implements bounded hierarchy traversal with caching and // role-based access control, providing efficient context resolution for // UCXL addresses through cascading inheritance patterns. type ContextResolver interface { // Resolve resolves context for a UCXL address using bounded hierarchy traversal // with default depth limits and role-based access control Resolve(ctx context.Context, address ucxl.Address, role string) (*ResolvedContext, error) // ResolveWithDepth resolves context with custom bounded depth limit // providing fine-grained control over hierarchy traversal depth for // performance optimization and resource management ResolveWithDepth(ctx context.Context, address ucxl.Address, role string, maxDepth int) (*ResolvedContext, error) // BatchResolve efficiently resolves multiple UCXL addresses in parallel // uses request deduplication, shared caching, and role-based filtering // for optimal performance with bulk operations BatchResolve(ctx context.Context, request *BatchResolutionRequest) (*BatchResolutionResult, error) // AddGlobalContext adds a global context that applies to all addresses // global contexts are automatically merged into all resolution results AddGlobalContext(ctx context.Context, globalCtx *ContextNode) error // SetHierarchyDepthLimit sets the maximum hierarchy depth for bounded traversal // prevents infinite loops and controls resource usage during resolution SetHierarchyDepthLimit(maxDepth int) // GetResolutionStatistics returns resolver performance and operational statistics GetStatistics() *ResolutionStatistics // InvalidateCache invalidates cached resolutions for an address pattern // useful for cache invalidation when contexts change InvalidateCache(pattern string) error // ClearCache clears all cached resolutions ClearCache() error } // HierarchyManager manages the context hierarchy with bounded traversal // // Provides operations for maintaining the hierarchical structure of // context nodes while enforcing depth limits and consistency constraints. type HierarchyManager interface { // LoadHierarchy loads the context hierarchy from storage LoadHierarchy(ctx context.Context) error // AddNode adds a context node to the hierarchy with validation AddNode(ctx context.Context, node *ContextNode) error // UpdateNode updates an existing context node UpdateNode(ctx context.Context, node *ContextNode) error // RemoveNode removes a context node and handles orphaned children RemoveNode(ctx context.Context, path string) error // GetNode retrieves a context node by path GetNode(ctx context.Context, path string) (*ContextNode, error) // TraverseUp traverses up the hierarchy with bounded depth TraverseUp(ctx context.Context, startPath string, maxDepth int) ([]*ContextNode, error) // TraverseDown traverses down the hierarchy with bounded depth TraverseDown(ctx context.Context, startPath string, maxDepth int) ([]*ContextNode, error) // GetChildren gets immediate children of a node GetChildren(ctx context.Context, path string) ([]*ContextNode, error) // GetParent gets the immediate parent of a node GetParent(ctx context.Context, path string) (*ContextNode, error) // ValidateHierarchy validates hierarchy integrity and constraints ValidateHierarchy(ctx context.Context) error // GetHierarchyStats returns statistics about the hierarchy GetHierarchyStats(ctx context.Context) (*HierarchyStats, error) } // GlobalContextManager manages global contexts that apply everywhere // // Global contexts provide system-wide applicable metadata that is // automatically included in all context resolutions regardless of // hierarchy position. type GlobalContextManager interface { // AddGlobalContext adds a context that applies globally AddGlobalContext(ctx context.Context, globalCtx *ContextNode) error // RemoveGlobalContext removes a global context RemoveGlobalContext(ctx context.Context, contextID string) error // UpdateGlobalContext updates an existing global context UpdateGlobalContext(ctx context.Context, globalCtx *ContextNode) error // ListGlobalContexts lists all global contexts ordered by priority ListGlobalContexts(ctx context.Context) ([]*ContextNode, error) // GetGlobalContext retrieves a specific global context GetGlobalContext(ctx context.Context, contextID string) (*ContextNode, error) // ApplyGlobalContexts applies global contexts to a resolution ApplyGlobalContexts(ctx context.Context, resolved *ResolvedContext) error // EnableGlobalContext enables/disables a global context EnableGlobalContext(ctx context.Context, contextID string, enabled bool) error // SetGlobalContextPriority sets priority for global context application SetGlobalContextPriority(ctx context.Context, contextID string, priority int) error } // CacheManager manages caching for context resolution performance type CacheManager interface { // Get retrieves a cached resolution Get(ctx context.Context, key string) (*ResolvedContext, error) // Set stores a resolution in cache with TTL Set(ctx context.Context, key string, resolved *ResolvedContext, ttl time.Duration) error // Delete removes a specific cache entry Delete(ctx context.Context, key string) error // DeletePattern removes cache entries matching a pattern DeletePattern(ctx context.Context, pattern string) error // Clear clears all cached entries Clear(ctx context.Context) error // GetStats returns cache performance statistics GetStats() *CacheStats } // CacheStats represents cache performance statistics type CacheStats struct { HitRate float64 `json:"hit_rate"` // Cache hit rate (0-1) MissRate float64 `json:"miss_rate"` // Cache miss rate (0-1) TotalHits int64 `json:"total_hits"` // Total cache hits TotalMisses int64 `json:"total_misses"` // Total cache misses CurrentSize int64 `json:"current_size"` // Current cache size MaxSize int64 `json:"max_size"` // Maximum cache size Evictions int64 `json:"evictions"` // Number of cache evictions LastEviction time.Time `json:"last_eviction"` // When last eviction occurred } // ContextMerger handles merging contexts during resolution type ContextMerger interface { // MergeContexts merges multiple contexts using inheritance rules MergeContexts(contexts []*ContextNode, options *MergeOptions) (*ResolvedContext, error) // MergeWithGlobal merges context with global contexts MergeWithGlobal(base *ResolvedContext, globals []*ContextNode) (*ResolvedContext, error) // CalculateSpecificity calculates context specificity for merge priority CalculateSpecificity(ctx *ContextNode) int // ValidateMergeResult validates merged context quality ValidateMergeResult(resolved *ResolvedContext) (*ValidationResult, error) } // ContextValidator validates context data quality and consistency type ContextValidator interface { // ValidateNode validates a single context node ValidateNode(ctx context.Context, node *ContextNode) (*ValidationResult, error) // ValidateResolved validates a resolved context ValidateResolved(ctx context.Context, resolved *ResolvedContext) (*ValidationResult, error) // ValidateHierarchyConsistency validates hierarchy-wide consistency ValidateHierarchyConsistency(ctx context.Context) ([]*ValidationIssue, error) // SuggestImprovements suggests improvements for context quality SuggestImprovements(ctx context.Context, node *ContextNode) ([]string, error) } // Helper functions and integration examples // ValidateContextResolutionRequest validates a context resolution request func ValidateContextResolutionRequest(address ucxl.Address, role string, maxDepth int) error { if err := address.Validate(); err != nil { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, "invalid UCXL address in resolution request").WithUnderlying(err).WithAddress(address) } if role == "" { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, "role cannot be empty in resolution request").WithAddress(address) } if maxDepth < 0 { return NewContextError(ErrorTypeValidation, ErrorCodeDepthExceeded, "maxDepth cannot be negative").WithAddress(address). WithContext("max_depth", fmt.Sprintf("%d", maxDepth)) } if maxDepth > 50 { // Reasonable upper bound to prevent resource exhaustion return NewContextError(ErrorTypeValidation, ErrorCodeDepthExceeded, "maxDepth exceeds reasonable limits").WithAddress(address). WithContext("max_depth", fmt.Sprintf("%d", maxDepth)) } return nil } // ValidateBatchResolutionRequest validates a batch resolution request func ValidateBatchResolutionRequest(request *BatchResolutionRequest) error { if request == nil { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "batch resolution request cannot be nil") } if len(request.Addresses) == 0 { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "batch resolution request must contain at least one address") } if len(request.Addresses) > 100 { // Prevent excessive batch sizes return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "batch resolution request exceeds maximum size"). WithContext("size", fmt.Sprintf("%d", len(request.Addresses))) } for i, address := range request.Addresses { if err := address.Validate(); err != nil { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, fmt.Sprintf("invalid address at index %d", i)).WithUnderlying(err).WithAddress(address) } } if request.Role == "" { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, "role cannot be empty in batch resolution request") } if request.MaxDepth < 0 { return NewContextError(ErrorTypeValidation, ErrorCodeDepthExceeded, "maxDepth cannot be negative in batch resolution request"). WithContext("max_depth", fmt.Sprintf("%d", request.MaxDepth)) } return nil } // CalculateResolutionConfidence calculates overall confidence from multiple context nodes func CalculateResolutionConfidence(contexts []*ContextNode) float64 { if len(contexts) == 0 { return 0.0 } totalConfidence := 0.0 totalWeight := 0.0 for _, ctx := range contexts { // Weight by specificity - higher specificity contexts have more influence weight := float64(ctx.ContextSpecificity + 1) totalConfidence += ctx.RAGConfidence * weight totalWeight += weight } if totalWeight == 0 { return 0.0 } confidence := totalConfidence / totalWeight // Apply diminishing returns for multiple contexts if len(contexts) > 1 { // Slight boost for having multiple confirming contexts, but not linear multiplier := 1.0 + (float64(len(contexts)-1) * 0.1) confidence = confidence * multiplier if confidence > 1.0 { confidence = 1.0 } } return confidence } // FilterContextsByRole filters context nodes based on role access func FilterContextsByRole(contexts []*ContextNode, role string, authority config.AuthorityLevel) []*ContextNode { filtered := make([]*ContextNode, 0, len(contexts)) for _, ctx := range contexts { if ctx.CanAccess(role, authority) { filtered = append(filtered, ctx) } } return filtered } // MergeStringSlices merges multiple string slices with deduplication func MergeStringSlices(slices ...[]string) []string { seen := make(map[string]bool) var result []string for _, slice := range slices { for _, item := range slice { if !seen[item] && item != "" { seen[item] = true result = append(result, item) } } } return result } // BuildInheritanceChain builds the inheritance chain for a resolved context func BuildInheritanceChain(contexts []*ContextNode) []string { chain := make([]string, 0, len(contexts)) // Sort by specificity (most specific first) for _, ctx := range contexts { chain = append(chain, ctx.Path) } return chain } // GenerateCacheKey generates a cache key for resolution requests func GenerateCacheKey(address ucxl.Address, role string, maxDepth int) string { return fmt.Sprintf("resolve:%s:%s:%d", address.String(), role, maxDepth) } // IsContextStale determines if a context node is stale and needs refresh func IsContextStale(ctx *ContextNode, staleTTL time.Duration) bool { return time.Since(ctx.GeneratedAt) > staleTTL } /* Integration Examples: 1. DHT Integration Example: // Store context in DHT with role-based encryption func (resolver *DefaultContextResolver) storeContextInDHT(ctx *ContextNode, roles []string) error { for _, role := range roles { // Encrypt context for role encrypted, err := resolver.crypto.EncryptForRole(ctx, role) if err != nil { return NewContextError(ErrorTypeEncryption, ErrorCodeEncryptionFailed, "failed to encrypt context for role").WithAddress(ctx.UCXLAddress). WithContext("role", role).WithUnderlying(err) } // Store in DHT key := fmt.Sprintf("context:%s:%s", ctx.UCXLAddress.String(), role) if err := resolver.dht.Put(key, encrypted); err != nil { return NewContextError(ErrorTypeDHT, ErrorCodeDHTError, "failed to store context in DHT").WithAddress(ctx.UCXLAddress). WithContext("role", role).WithUnderlying(err) } } return nil } 2. Leader Election Integration Example: // Context generation only happens on leader node func (manager *ContextManager) GenerateContextIfLeader(filePath string, role string) error { if !manager.IsLeader() { return NewContextError(ErrorTypeAccess, ErrorCodeAccessDenied, "context generation is only allowed on leader nodes"). WithContext("current_role", "follower") } // Parse UCXL address from file path address, err := manager.pathResolver.PathToUCXL(filePath) if err != nil { return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, "failed to resolve file path to UCXL address").WithUnderlying(err). WithContext("file_path", filePath) } // Generate context using intelligence engine ctx, err := manager.intelligence.AnalyzeFile(context.Background(), filePath, role) if err != nil { return NewContextError(ErrorTypeIntelligence, ErrorCodeInternalError, "failed to generate context").WithAddress(*address).WithUnderlying(err) } // Store in hierarchy manager if err := manager.hierarchyManager.AddNode(context.Background(), ctx); err != nil { return NewContextError(ErrorTypeHierarchy, ErrorCodeStorageError, "failed to add context to hierarchy").WithAddress(ctx.UCXLAddress). WithUnderlying(err) } // Distribute via DHT for role-based access roles := manager.getRolesForContext(ctx) return manager.distributor.DistributeContext(ctx, roles) } 3. Crypto Integration Example: // Decrypt context based on role authority func (resolver *DefaultContextResolver) decryptContextForRole(encrypted []byte, role string) (*ContextNode, error) { // Check if current agent can decrypt this role's content canDecrypt, err := resolver.config.CanDecryptRole(role) if err != nil { return nil, NewContextError(ErrorTypeAccess, ErrorCodeInvalidRole, "failed to check decryption permissions").WithContext("role", role). WithUnderlying(err) } if !canDecrypt { return nil, NewContextError(ErrorTypeAccess, ErrorCodeAccessDenied, "insufficient authority to decrypt context").WithContext("role", role). WithContext("current_role", resolver.config.Agent.Role) } // Decrypt using role's private key decrypted, err := resolver.crypto.DecryptWithRole(encrypted) if err != nil { return nil, NewContextError(ErrorTypeEncryption, ErrorCodeDecryptionFailed, "failed to decrypt context").WithContext("role", role).WithUnderlying(err) } // Deserialize context var ctx ContextNode if err := json.Unmarshal(decrypted, &ctx); err != nil { return nil, NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "failed to deserialize decrypted context").WithUnderlying(err) } return &ctx, nil } 4. Complete Resolution Flow Example: // Resolve context with full BZZZ integration func (resolver *DefaultContextResolver) ResolveWithIntegration(ctx context.Context, address ucxl.Address, role string, maxDepth int) (*ResolvedContext, error) { // 1. Validate request if err := ValidateContextResolutionRequest(address, role, maxDepth); err != nil { return nil, err } // 2. Check cache first cacheKey := GenerateCacheKey(address, role, maxDepth) if cached, err := resolver.cache.Get(ctx, cacheKey); err == nil { resolver.stats.CacheHits++ return cached, nil } resolver.stats.CacheMisses++ // 3. Try local hierarchy first localContexts, err := resolver.hierarchyManager.TraverseUp(ctx, address.Path, maxDepth) if err != nil { return nil, NewContextError(ErrorTypeHierarchy, ErrorCodeStorageError, "failed to traverse local hierarchy").WithAddress(address).WithUnderlying(err) } // 4. If no local contexts, try DHT var dhtContexts []*ContextNode if len(localContexts) == 0 { dhtContext, err := resolver.fetchContextFromDHT(address, role) if err == nil { dhtContexts = []*ContextNode{dhtContext} } } // 5. Combine local and DHT contexts allContexts := append(localContexts, dhtContexts...) if len(allContexts) == 0 { return nil, NewContextError(ErrorTypeResolution, ErrorCodeNotFound, "no context found for address").WithAddress(address) } // 6. Filter by role access authority, err := resolver.config.GetRoleAuthority(role) if err != nil { return nil, NewContextError(ErrorTypeAccess, ErrorCodeInvalidRole, "failed to get role authority").WithContext("role", role).WithUnderlying(err) } accessibleContexts := FilterContextsByRole(allContexts, role, authority) if len(accessibleContexts) == 0 { return nil, NewContextError(ErrorTypeAccess, ErrorCodeAccessDenied, "no accessible contexts for role").WithAddress(address).WithContext("role", role) } // 7. Merge contexts using inheritance rules resolved, err := resolver.merger.MergeContexts(accessibleContexts, resolver.mergeOptions) if err != nil { return nil, NewContextError(ErrorTypeResolution, ErrorCodeInternalError, "failed to merge contexts").WithAddress(address).WithUnderlying(err) } // 8. Apply global contexts if enabled if resolver.globalContextsEnabled { globalContexts, err := resolver.globalManager.ListGlobalContexts(ctx) if err == nil && len(globalContexts) > 0 { resolved, err = resolver.merger.MergeWithGlobal(resolved, globalContexts) if err != nil { return nil, NewContextError(ErrorTypeResolution, ErrorCodeInternalError, "failed to apply global contexts").WithAddress(address).WithUnderlying(err) } resolved.GlobalContextsApplied = true } } // 9. Validate resolved context if err := resolved.Validate(); err != nil { return nil, NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "resolved context failed validation").WithAddress(address).WithUnderlying(err) } // 10. Cache the result if err := resolver.cache.Set(ctx, cacheKey, resolved, resolver.cacheTTL); err != nil { // Log but don't fail the request resolver.logger.Warn("failed to cache resolved context", "error", err) } // 11. Update statistics resolver.stats.TotalResolutions++ return resolved, nil } */