Align SLURP access control with config authority levels

This commit is contained in:
anthonyrawlins
2025-09-27 15:33:23 +10:00
parent 0b670a535d
commit a99469f346
3 changed files with 157 additions and 148 deletions

View File

@@ -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

View File

@@ -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": {

View File

@@ -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
}
}