diff --git a/pkg/config/config.go b/pkg/config/config.go index 2a1aab4..5a1beb5 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -274,14 +274,13 @@ func (c *Config) ApplyRoleDefinition(role string) error { } // GetRoleAuthority returns the authority level for a role (from CHORUS) -func (c *Config) GetRoleAuthority(role string) (string, error) { - // This would contain the authority mapping from CHORUS - switch role { - case "admin": - return "master", nil - default: - return "member", nil +func (c *Config) GetRoleAuthority(role string) (AuthorityLevel, error) { + roles := GetPredefinedRoles() + if def, ok := roles[role]; ok { + return def.AuthorityLevel, nil } + + return AuthorityReadOnly, fmt.Errorf("unknown role: %s", role) } // Helper functions for environment variable parsing diff --git a/pkg/config/security.go b/pkg/config/security.go index b490bcc..2e6bc86 100644 --- a/pkg/config/security.go +++ b/pkg/config/security.go @@ -2,12 +2,18 @@ package config import "time" -// Authority levels for roles +// AuthorityLevel represents the privilege tier associated with a role. +type AuthorityLevel string + +// Authority levels for roles (aligned with CHORUS hierarchy). const ( - AuthorityReadOnly = "readonly" - AuthoritySuggestion = "suggestion" - AuthorityFull = "full" - AuthorityAdmin = "admin" + AuthorityMaster AuthorityLevel = "master" + AuthorityAdmin AuthorityLevel = "admin" + AuthorityDecision AuthorityLevel = "decision" + AuthorityCoordination AuthorityLevel = "coordination" + AuthorityFull AuthorityLevel = "full" + AuthoritySuggestion AuthorityLevel = "suggestion" + AuthorityReadOnly AuthorityLevel = "readonly" ) // SecurityConfig defines security-related configuration @@ -43,14 +49,14 @@ type AgeKeyPair struct { // RoleDefinition represents a role configuration type RoleDefinition struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - Capabilities []string `yaml:"capabilities"` - AccessLevel string `yaml:"access_level"` - AuthorityLevel string `yaml:"authority_level"` - Keys *AgeKeyPair `yaml:"keys,omitempty"` - AgeKeys *AgeKeyPair `yaml:"age_keys,omitempty"` // Legacy field name - CanDecrypt []string `yaml:"can_decrypt,omitempty"` // Roles this role can decrypt + Name string `yaml:"name"` + Description string `yaml:"description"` + Capabilities []string `yaml:"capabilities"` + AccessLevel string `yaml:"access_level"` + AuthorityLevel AuthorityLevel `yaml:"authority_level"` + Keys *AgeKeyPair `yaml:"keys,omitempty"` + AgeKeys *AgeKeyPair `yaml:"age_keys,omitempty"` // Legacy field name + CanDecrypt []string `yaml:"can_decrypt,omitempty"` // Roles this role can decrypt } // GetPredefinedRoles returns the predefined roles for the system @@ -61,7 +67,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Project coordination and management", Capabilities: []string{"coordination", "planning", "oversight"}, AccessLevel: "high", - AuthorityLevel: AuthorityAdmin, + AuthorityLevel: AuthorityMaster, CanDecrypt: []string{"project_manager", "backend_developer", "frontend_developer", "devops_engineer", "security_engineer"}, }, "backend_developer": { @@ -69,7 +75,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Backend development and API work", Capabilities: []string{"backend", "api", "database"}, AccessLevel: "medium", - AuthorityLevel: AuthorityFull, + AuthorityLevel: AuthorityDecision, CanDecrypt: []string{"backend_developer"}, }, "frontend_developer": { @@ -77,7 +83,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Frontend UI development", Capabilities: []string{"frontend", "ui", "components"}, AccessLevel: "medium", - AuthorityLevel: AuthorityFull, + AuthorityLevel: AuthorityCoordination, CanDecrypt: []string{"frontend_developer"}, }, "devops_engineer": { @@ -85,7 +91,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Infrastructure and deployment", Capabilities: []string{"infrastructure", "deployment", "monitoring"}, AccessLevel: "high", - AuthorityLevel: AuthorityFull, + AuthorityLevel: AuthorityDecision, CanDecrypt: []string{"devops_engineer", "backend_developer"}, }, "security_engineer": { @@ -93,7 +99,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Security oversight and hardening", Capabilities: []string{"security", "audit", "compliance"}, AccessLevel: "high", - AuthorityLevel: AuthorityAdmin, + AuthorityLevel: AuthorityMaster, CanDecrypt: []string{"security_engineer", "project_manager", "backend_developer", "frontend_developer", "devops_engineer"}, }, "security_expert": { @@ -101,7 +107,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Advanced security analysis and policy work", Capabilities: []string{"security", "policy", "response"}, AccessLevel: "high", - AuthorityLevel: AuthorityAdmin, + AuthorityLevel: AuthorityMaster, CanDecrypt: []string{"security_expert", "security_engineer", "project_manager"}, }, "senior_software_architect": { @@ -109,7 +115,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Architecture governance and system design", Capabilities: []string{"architecture", "design", "coordination"}, AccessLevel: "high", - AuthorityLevel: AuthorityAdmin, + AuthorityLevel: AuthorityDecision, CanDecrypt: []string{"senior_software_architect", "project_manager", "backend_developer", "frontend_developer"}, }, "qa_engineer": { @@ -117,7 +123,7 @@ func GetPredefinedRoles() map[string]*RoleDefinition { Description: "Quality assurance and testing", Capabilities: []string{"testing", "validation"}, AccessLevel: "medium", - AuthorityLevel: AuthorityFull, + AuthorityLevel: AuthorityCoordination, CanDecrypt: []string{"qa_engineer", "backend_developer", "frontend_developer"}, }, "readonly_user": { diff --git a/pkg/slurp/context/types.go b/pkg/slurp/context/types.go index 5fc993c..c0cac72 100644 --- a/pkg/slurp/context/types.go +++ b/pkg/slurp/context/types.go @@ -4,8 +4,8 @@ import ( "fmt" "time" - "chorus/pkg/ucxl" "chorus/pkg/config" + "chorus/pkg/ucxl" ) // ContextNode represents a hierarchical context node in the SLURP system. @@ -19,25 +19,25 @@ type ContextNode struct { UCXLAddress ucxl.Address `json:"ucxl_address"` // Associated UCXL address Summary string `json:"summary"` // Brief description Purpose string `json:"purpose"` // What this component does - + // Context metadata Technologies []string `json:"technologies"` // Technologies used Tags []string `json:"tags"` // Categorization tags Insights []string `json:"insights"` // Analytical insights - + // Hierarchy control - OverridesParent bool `json:"overrides_parent"` // Whether this overrides parent context - ContextSpecificity int `json:"context_specificity"` // Specificity level (higher = more specific) - AppliesToChildren bool `json:"applies_to_children"` // Whether this applies to child directories - + OverridesParent bool `json:"overrides_parent"` // Whether this overrides parent context + ContextSpecificity int `json:"context_specificity"` // Specificity level (higher = more specific) + AppliesToChildren bool `json:"applies_to_children"` // Whether this applies to child directories + // Metadata GeneratedAt time.Time `json:"generated_at"` // When context was generated RAGConfidence float64 `json:"rag_confidence"` // RAG system confidence (0-1) - + // Access control - EncryptedFor []string `json:"encrypted_for"` // Roles that can access - AccessLevel RoleAccessLevel `json:"access_level"` // Required access level - + EncryptedFor []string `json:"encrypted_for"` // Roles that can access + AccessLevel RoleAccessLevel `json:"access_level"` // Required access level + // Custom metadata Metadata map[string]interface{} `json:"metadata,omitempty"` // Additional metadata } @@ -47,11 +47,11 @@ type ContextNode struct { type RoleAccessLevel int const ( - AccessPublic RoleAccessLevel = iota // Anyone can access - AccessLow // Basic role access - AccessMedium // Coordination role access - AccessHigh // Decision role access - AccessCritical // Master role access only + AccessPublic RoleAccessLevel = iota // Anyone can access + AccessLow // Basic role access + AccessMedium // Coordination role access + AccessHigh // Decision role access + AccessCritical // Master role access only ) // EncryptedContext represents role-encrypted context data for DHT storage @@ -75,26 +75,26 @@ type ResolvedContext struct { Technologies []string `json:"technologies"` // Merged technologies Tags []string `json:"tags"` // Merged tags Insights []string `json:"insights"` // Merged insights - + // Resolution metadata - ContextSourcePath string `json:"context_source_path"` // Primary source context path - InheritanceChain []string `json:"inheritance_chain"` // Context inheritance chain - ResolutionConfidence float64 `json:"resolution_confidence"` // Overall confidence (0-1) - BoundedDepth int `json:"bounded_depth"` // Actual traversal depth used - GlobalContextsApplied bool `json:"global_contexts_applied"` // Whether global contexts were applied - ResolvedAt time.Time `json:"resolved_at"` // When resolution occurred + ContextSourcePath string `json:"context_source_path"` // Primary source context path + InheritanceChain []string `json:"inheritance_chain"` // Context inheritance chain + ResolutionConfidence float64 `json:"resolution_confidence"` // Overall confidence (0-1) + BoundedDepth int `json:"bounded_depth"` // Actual traversal depth used + GlobalContextsApplied bool `json:"global_contexts_applied"` // Whether global contexts were applied + ResolvedAt time.Time `json:"resolved_at"` // When resolution occurred } // ResolutionStatistics represents statistics about context resolution operations type ResolutionStatistics struct { - ContextNodes int `json:"context_nodes"` // Total context nodes in hierarchy - GlobalContexts int `json:"global_contexts"` // Number of global contexts - MaxHierarchyDepth int `json:"max_hierarchy_depth"` // Maximum hierarchy depth allowed - CachedResolutions int `json:"cached_resolutions"` // Number of cached resolutions - TotalResolutions int `json:"total_resolutions"` // Total resolution operations - AverageDepth float64 `json:"average_depth"` // Average traversal depth - CacheHitRate float64 `json:"cache_hit_rate"` // Cache hit rate (0-1) - LastResetAt time.Time `json:"last_reset_at"` // When stats were last reset + ContextNodes int `json:"context_nodes"` // Total context nodes in hierarchy + GlobalContexts int `json:"global_contexts"` // Number of global contexts + MaxHierarchyDepth int `json:"max_hierarchy_depth"` // Maximum hierarchy depth allowed + CachedResolutions int `json:"cached_resolutions"` // Number of cached resolutions + TotalResolutions int `json:"total_resolutions"` // Total resolution operations + AverageDepth float64 `json:"average_depth"` // Average traversal depth + CacheHitRate float64 `json:"cache_hit_rate"` // Cache hit rate (0-1) + LastResetAt time.Time `json:"last_reset_at"` // When stats were last reset } // ContextScope defines the scope of a context node's application @@ -108,25 +108,25 @@ const ( // HierarchyStats represents statistics about hierarchy operations type HierarchyStats struct { - NodesCreated int `json:"nodes_created"` // Number of nodes created - NodesUpdated int `json:"nodes_updated"` // Number of nodes updated - FilesAnalyzed int `json:"files_analyzed"` // Number of files analyzed - DirectoriesScanned int `json:"directories_scanned"` // Number of directories scanned - GenerationTime time.Duration `json:"generation_time"` // Time taken for generation - AverageConfidence float64 `json:"average_confidence"` // Average confidence score - TotalSize int64 `json:"total_size"` // Total size of analyzed content - SkippedFiles int `json:"skipped_files"` // Number of files skipped - Errors []string `json:"errors"` // Generation errors + NodesCreated int `json:"nodes_created"` // Number of nodes created + NodesUpdated int `json:"nodes_updated"` // Number of nodes updated + FilesAnalyzed int `json:"files_analyzed"` // Number of files analyzed + DirectoriesScanned int `json:"directories_scanned"` // Number of directories scanned + GenerationTime time.Duration `json:"generation_time"` // Time taken for generation + AverageConfidence float64 `json:"average_confidence"` // Average confidence score + TotalSize int64 `json:"total_size"` // Total size of analyzed content + SkippedFiles int `json:"skipped_files"` // Number of files skipped + Errors []string `json:"errors"` // Generation errors } // CacheEntry represents a cached context resolution type CacheEntry struct { - Key string `json:"key"` // Cache key - ResolvedCtx *ResolvedContext `json:"resolved_ctx"` // Cached resolved context - CreatedAt time.Time `json:"created_at"` // When cached - ExpiresAt time.Time `json:"expires_at"` // When cache expires - AccessCount int `json:"access_count"` // Number of times accessed - LastAccessed time.Time `json:"last_accessed"` // When last accessed + Key string `json:"key"` // Cache key + ResolvedCtx *ResolvedContext `json:"resolved_ctx"` // Cached resolved context + CreatedAt time.Time `json:"created_at"` // When cached + ExpiresAt time.Time `json:"expires_at"` // When cache expires + AccessCount int `json:"access_count"` // Number of times accessed + LastAccessed time.Time `json:"last_accessed"` // When last accessed } // ValidationResult represents the result of context validation @@ -149,13 +149,13 @@ type ValidationIssue struct { // MergeOptions defines options for merging contexts during resolution type MergeOptions struct { - PreferParent bool `json:"prefer_parent"` // Prefer parent values over child - MergeTechnologies bool `json:"merge_technologies"` // Merge technology lists - MergeTags bool `json:"merge_tags"` // Merge tag lists - MergeInsights bool `json:"merge_insights"` // Merge insight lists - ExcludedFields []string `json:"excluded_fields"` // Fields to exclude from merge - WeightParentByDepth bool `json:"weight_parent_by_depth"` // Weight parent influence by depth - MinConfidenceThreshold float64 `json:"min_confidence_threshold"` // Minimum confidence to include + PreferParent bool `json:"prefer_parent"` // Prefer parent values over child + MergeTechnologies bool `json:"merge_technologies"` // Merge technology lists + MergeTags bool `json:"merge_tags"` // Merge tag lists + MergeInsights bool `json:"merge_insights"` // Merge insight lists + ExcludedFields []string `json:"excluded_fields"` // Fields to exclude from merge + WeightParentByDepth bool `json:"weight_parent_by_depth"` // Weight parent influence by depth + MinConfidenceThreshold float64 `json:"min_confidence_threshold"` // Minimum confidence to include } // BatchResolutionRequest represents a batch resolution request @@ -178,12 +178,12 @@ type BatchResolutionResult struct { // ContextError represents a context-related error with structured information type ContextError struct { - Type string `json:"type"` // Error type (validation, resolution, access, etc.) - Message string `json:"message"` // Human-readable error message - Code string `json:"code"` // Machine-readable error code - Address *ucxl.Address `json:"address"` // Related UCXL address if applicable - Context map[string]string `json:"context"` // Additional context information - Underlying error `json:"underlying"` // Underlying error if any + Type string `json:"type"` // Error type (validation, resolution, access, etc.) + Message string `json:"message"` // Human-readable error message + Code string `json:"code"` // Machine-readable error code + Address *ucxl.Address `json:"address"` // Related UCXL address if applicable + Context map[string]string `json:"context"` // Additional context information + Underlying error `json:"underlying"` // Underlying error if any } func (e *ContextError) Error() string { @@ -199,34 +199,34 @@ func (e *ContextError) Unwrap() error { // Common error types and codes const ( - ErrorTypeValidation = "validation" - ErrorTypeResolution = "resolution" - ErrorTypeAccess = "access" - ErrorTypeStorage = "storage" - ErrorTypeEncryption = "encryption" - ErrorTypeDHT = "dht" - ErrorTypeHierarchy = "hierarchy" - ErrorTypeCache = "cache" - ErrorTypeTemporalGraph = "temporal_graph" - ErrorTypeIntelligence = "intelligence" + ErrorTypeValidation = "validation" + ErrorTypeResolution = "resolution" + ErrorTypeAccess = "access" + ErrorTypeStorage = "storage" + ErrorTypeEncryption = "encryption" + ErrorTypeDHT = "dht" + ErrorTypeHierarchy = "hierarchy" + ErrorTypeCache = "cache" + ErrorTypeTemporalGraph = "temporal_graph" + ErrorTypeIntelligence = "intelligence" ) const ( - ErrorCodeInvalidAddress = "invalid_address" - ErrorCodeInvalidContext = "invalid_context" - ErrorCodeInvalidRole = "invalid_role" - ErrorCodeAccessDenied = "access_denied" - ErrorCodeNotFound = "not_found" - ErrorCodeDepthExceeded = "depth_exceeded" - ErrorCodeCycleDetected = "cycle_detected" - ErrorCodeEncryptionFailed = "encryption_failed" - ErrorCodeDecryptionFailed = "decryption_failed" - ErrorCodeDHTError = "dht_error" - ErrorCodeCacheError = "cache_error" - ErrorCodeStorageError = "storage_error" - ErrorCodeInvalidConfig = "invalid_config" - ErrorCodeTimeout = "timeout" - ErrorCodeInternalError = "internal_error" + ErrorCodeInvalidAddress = "invalid_address" + ErrorCodeInvalidContext = "invalid_context" + ErrorCodeInvalidRole = "invalid_role" + ErrorCodeAccessDenied = "access_denied" + ErrorCodeNotFound = "not_found" + ErrorCodeDepthExceeded = "depth_exceeded" + ErrorCodeCycleDetected = "cycle_detected" + ErrorCodeEncryptionFailed = "encryption_failed" + ErrorCodeDecryptionFailed = "decryption_failed" + ErrorCodeDHTError = "dht_error" + ErrorCodeCacheError = "cache_error" + ErrorCodeStorageError = "storage_error" + ErrorCodeInvalidConfig = "invalid_config" + ErrorCodeTimeout = "timeout" + ErrorCodeInternalError = "internal_error" ) // NewContextError creates a new context error with structured information @@ -292,7 +292,7 @@ func ParseRoleAccessLevel(level string) (RoleAccessLevel, error) { case "critical": return AccessCritical, nil default: - return AccessPublic, NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, + return AccessPublic, NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, fmt.Sprintf("invalid role access level: %s", level)) } } @@ -302,8 +302,12 @@ func AuthorityToAccessLevel(authority config.AuthorityLevel) RoleAccessLevel { switch authority { case config.AuthorityMaster: return AccessCritical + case config.AuthorityAdmin: + return AccessCritical case config.AuthorityDecision: return AccessHigh + case config.AuthorityFull: + return AccessHigh case config.AuthorityCoordination: return AccessMedium case config.AuthoritySuggestion: @@ -322,23 +326,23 @@ func (cn *ContextNode) Validate() error { } if err := cn.UCXLAddress.Validate(); err != nil { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, "invalid UCXL address").WithUnderlying(err).WithAddress(cn.UCXLAddress) } if cn.Summary == "" { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "context summary cannot be empty").WithAddress(cn.UCXLAddress) } if cn.RAGConfidence < 0 || cn.RAGConfidence > 1 { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "RAG confidence must be between 0 and 1").WithAddress(cn.UCXLAddress). WithContext("confidence", fmt.Sprintf("%.2f", cn.RAGConfidence)) } if cn.ContextSpecificity < 0 { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "context specificity cannot be negative").WithAddress(cn.UCXLAddress). WithContext("specificity", fmt.Sprintf("%d", cn.ContextSpecificity)) } @@ -346,7 +350,7 @@ func (cn *ContextNode) Validate() error { // Validate role access levels for _, role := range cn.EncryptedFor { if role == "" { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidRole, "encrypted_for roles cannot be empty").WithAddress(cn.UCXLAddress) } } @@ -354,32 +358,32 @@ func (cn *ContextNode) Validate() error { return nil } -// Validate validates a ResolvedContext for consistency and completeness +// Validate validates a ResolvedContext for consistency and completeness func (rc *ResolvedContext) Validate() error { if err := rc.UCXLAddress.Validate(); err != nil { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidAddress, "invalid UCXL address in resolved context").WithUnderlying(err).WithAddress(rc.UCXLAddress) } if rc.Summary == "" { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "resolved context summary cannot be empty").WithAddress(rc.UCXLAddress) } if rc.ResolutionConfidence < 0 || rc.ResolutionConfidence > 1 { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "resolution confidence must be between 0 and 1").WithAddress(rc.UCXLAddress). WithContext("confidence", fmt.Sprintf("%.2f", rc.ResolutionConfidence)) } if rc.BoundedDepth < 0 { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "bounded depth cannot be negative").WithAddress(rc.UCXLAddress). WithContext("depth", fmt.Sprintf("%d", rc.BoundedDepth)) } if rc.ContextSourcePath == "" { - return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, + return NewContextError(ErrorTypeValidation, ErrorCodeInvalidContext, "context source path cannot be empty").WithAddress(rc.UCXLAddress) } @@ -398,8 +402,8 @@ func (cn *ContextNode) HasRole(role string) bool { // CanAccess checks if a role can access this context based on authority level func (cn *ContextNode) CanAccess(role string, authority config.AuthorityLevel) bool { - // Master authority can access everything - if authority == config.AuthorityMaster { + // Master/Admin authority can access everything + if authority == config.AuthorityMaster || authority == config.AuthorityAdmin { return true } @@ -421,16 +425,16 @@ func (cn *ContextNode) Clone() *ContextNode { Summary: cn.Summary, Purpose: cn.Purpose, Technologies: make([]string, len(cn.Technologies)), - Tags: make([]string, len(cn.Tags)), - Insights: make([]string, len(cn.Insights)), - OverridesParent: cn.OverridesParent, + Tags: make([]string, len(cn.Tags)), + Insights: make([]string, len(cn.Insights)), + OverridesParent: cn.OverridesParent, ContextSpecificity: cn.ContextSpecificity, - AppliesToChildren: cn.AppliesToChildren, - GeneratedAt: cn.GeneratedAt, - RAGConfidence: cn.RAGConfidence, - EncryptedFor: make([]string, len(cn.EncryptedFor)), - AccessLevel: cn.AccessLevel, - Metadata: make(map[string]interface{}), + AppliesToChildren: cn.AppliesToChildren, + GeneratedAt: cn.GeneratedAt, + RAGConfidence: cn.RAGConfidence, + EncryptedFor: make([]string, len(cn.EncryptedFor)), + AccessLevel: cn.AccessLevel, + Metadata: make(map[string]interface{}), } copy(cloned.Technologies, cn.Technologies) @@ -448,18 +452,18 @@ func (cn *ContextNode) Clone() *ContextNode { // Clone creates a deep copy of the ResolvedContext func (rc *ResolvedContext) Clone() *ResolvedContext { cloned := &ResolvedContext{ - UCXLAddress: *rc.UCXLAddress.Clone(), - Summary: rc.Summary, - Purpose: rc.Purpose, - Technologies: make([]string, len(rc.Technologies)), - Tags: make([]string, len(rc.Tags)), - Insights: make([]string, len(rc.Insights)), - ContextSourcePath: rc.ContextSourcePath, - InheritanceChain: make([]string, len(rc.InheritanceChain)), - ResolutionConfidence: rc.ResolutionConfidence, - BoundedDepth: rc.BoundedDepth, - GlobalContextsApplied: rc.GlobalContextsApplied, - ResolvedAt: rc.ResolvedAt, + UCXLAddress: *rc.UCXLAddress.Clone(), + Summary: rc.Summary, + Purpose: rc.Purpose, + Technologies: make([]string, len(rc.Technologies)), + Tags: make([]string, len(rc.Tags)), + Insights: make([]string, len(rc.Insights)), + ContextSourcePath: rc.ContextSourcePath, + InheritanceChain: make([]string, len(rc.InheritanceChain)), + ResolutionConfidence: rc.ResolutionConfidence, + BoundedDepth: rc.BoundedDepth, + GlobalContextsApplied: rc.GlobalContextsApplied, + ResolvedAt: rc.ResolvedAt, } copy(cloned.Technologies, rc.Technologies) @@ -468,4 +472,4 @@ func (rc *ResolvedContext) Clone() *ResolvedContext { copy(cloned.InheritanceChain, rc.InheritanceChain) return cloned -} \ No newline at end of file +}