package intelligence import ( "context" "fmt" "math" "sort" "strings" "sync" "time" slurpContext "chorus/pkg/slurp/context" ) // GoalAlignmentEngine provides comprehensive goal alignment assessment type GoalAlignmentEngine struct { mu sync.RWMutex config *EngineConfig scoringEngine *ScoringEngine dimensionAnalyzer *DimensionAnalyzer priorityCalculator *PriorityCalculator trendAnalyzer *TrendAnalyzer recommendationEngine *RecommendationEngine metrics *AlignmentMetrics } // ScoringEngine handles multi-dimensional scoring algorithms type ScoringEngine struct { dimensions []*ScoringDimension weightConfig *WeightConfiguration normalizer *ScoreNormalizer aggregator *ScoreAggregator } // ScoringDimension represents a single dimension of goal alignment type ScoringDimension struct { Name string `json:"name"` Description string `json:"description"` Weight float64 `json:"weight"` Calculator DimensionCalculator `json:"-"` Threshold float64 `json:"threshold"` Priority int `json:"priority"` Category string `json:"category"` Metadata map[string]interface{} `json:"metadata"` } // DimensionCalculator interface for calculating dimension scores type DimensionCalculator interface { Calculate(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) (*DimensionScore, error) GetName() string GetWeight() float64 Validate(node *slurpContext.ContextNode, goal *ProjectGoal) error } // DimensionScore represents a score for a single dimension type DimensionScore struct { Dimension string `json:"dimension"` Score float64 `json:"score"` Confidence float64 `json:"confidence"` Evidence []string `json:"evidence"` Reasoning string `json:"reasoning"` SubScores map[string]float64 `json:"sub_scores"` Metadata map[string]interface{} `json:"metadata"` CalculatedAt time.Time `json:"calculated_at"` } // WeightConfiguration manages dimension weights type WeightConfiguration struct { GlobalWeights map[string]float64 `json:"global_weights"` RoleWeights map[string]map[string]float64 `json:"role_weights"` PhaseWeights map[string]map[string]float64 `json:"phase_weights"` ProjectWeights map[string]map[string]float64 `json:"project_weights"` DynamicWeights bool `json:"dynamic_weights"` LastUpdated time.Time `json:"last_updated"` } // ScoreNormalizer normalizes scores across different dimensions type ScoreNormalizer struct { normalizationMethod string referenceData *NormalizationReference } // NormalizationReference contains reference data for normalization type NormalizationReference struct { HistoricalScores map[string]*ScoreDistribution `json:"historical_scores"` Percentiles map[string]map[int]float64 `json:"percentiles"` LastCalculated time.Time `json:"last_calculated"` } // ScoreDistribution represents score distribution statistics type ScoreDistribution struct { Mean float64 `json:"mean"` Median float64 `json:"median"` StdDev float64 `json:"std_dev"` Min float64 `json:"min"` Max float64 `json:"max"` Count int `json:"count"` Samples []float64 `json:"samples"` } // ScoreAggregator combines dimension scores into final alignment score type ScoreAggregator struct { method string customLogic func([]*DimensionScore, *WeightConfiguration) float64 } // DimensionAnalyzer analyzes alignment dimensions type DimensionAnalyzer struct { calculators map[string]DimensionCalculator } // PriorityCalculator calculates priority-based scoring adjustments type PriorityCalculator struct { priorityMatrix *PriorityMatrix timeFactors *TimeFactors } // PriorityMatrix defines priority relationships type PriorityMatrix struct { Goals map[string]int `json:"goals"` Phases map[string]int `json:"phases"` Technologies map[string]int `json:"technologies"` Roles map[string]int `json:"roles"` Urgency map[string]float64 `json:"urgency"` Impact map[string]float64 `json:"impact"` } // TimeFactors handles time-based priority adjustments type TimeFactors struct { DecayFunction string `json:"decay_function"` HalfLife time.Duration `json:"half_life"` UrgencyBoost float64 `json:"urgency_boost"` DeadlineWeight float64 `json:"deadline_weight"` PhaseAlignment map[string]float64 `json:"phase_alignment"` } // TrendAnalyzer analyzes alignment trends over time type TrendAnalyzer struct { historicalData *AlignmentHistory trendDetector *TrendDetector predictor *AlignmentPredictor } // AlignmentHistory stores historical alignment data type AlignmentHistory struct { mu sync.RWMutex records []*AlignmentRecord maxRecords int retention time.Duration } // AlignmentRecord represents a historical alignment record type AlignmentRecord struct { NodePath string `json:"node_path"` GoalID string `json:"goal_id"` Score float64 `json:"score"` Dimensions []*DimensionScore `json:"dimensions"` Context map[string]interface{} `json:"context"` Timestamp time.Time `json:"timestamp"` Role string `json:"role"` Phase string `json:"phase"` } // TrendDetector detects trends in alignment data type TrendDetector struct { methods []TrendDetectionMethod } // TrendDetectionMethod interface for trend detection algorithms type TrendDetectionMethod interface { DetectTrend(data []*AlignmentRecord) (*Trend, error) GetName() string GetConfidence() float64 } // Trend represents a detected trend type Trend struct { Type string `json:"type"` // improving, declining, stable, volatile Strength float64 `json:"strength"` // 0-1 strength of trend Confidence float64 `json:"confidence"` // 0-1 confidence in detection Duration time.Duration `json:"duration"` // duration of trend Slope float64 `json:"slope"` // rate of change Breakpoints []time.Time `json:"breakpoints"` // trend change points Description string `json:"description"` StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` } // AlignmentPredictor predicts future alignment scores type AlignmentPredictor struct { models []PredictionModel } // PredictionModel interface for alignment prediction type PredictionModel interface { Predict(ctx context.Context, history []*AlignmentRecord, horizon time.Duration) (*AlignmentPrediction, error) GetName() string GetAccuracy() float64 Train(data []*AlignmentRecord) error } // AlignmentPrediction represents predicted alignment type AlignmentPrediction struct { PredictedScore float64 `json:"predicted_score"` ConfidenceInterval *ConfidenceInterval `json:"confidence_interval"` Factors map[string]float64 `json:"factors"` Scenarios []*Scenario `json:"scenarios"` Recommendations []string `json:"recommendations"` Horizon time.Duration `json:"horizon"` Model string `json:"model"` PredictedAt time.Time `json:"predicted_at"` } // ConfidenceInterval represents prediction confidence type ConfidenceInterval struct { Lower float64 `json:"lower"` Upper float64 `json:"upper"` Confidence float64 `json:"confidence"` // e.g., 0.95 for 95% confidence } // Scenario represents a prediction scenario type Scenario struct { Name string `json:"name"` Probability float64 `json:"probability"` Score float64 `json:"score"` Description string `json:"description"` Assumptions []string `json:"assumptions"` } // RecommendationEngine generates alignment improvement recommendations type RecommendationEngine struct { ruleEngine *RecommendationRuleEngine mlEngine *MLRecommendationEngine prioritizer *RecommendationPrioritizer } // RecommendationRuleEngine provides rule-based recommendations type RecommendationRuleEngine struct { rules []*RecommendationRule } // RecommendationRule defines a recommendation rule type RecommendationRule struct { ID string `json:"id"` Name string `json:"name"` Condition RecommendationCondition `json:"condition"` Action RecommendationAction `json:"action"` Priority int `json:"priority"` Confidence float64 `json:"confidence"` Category string `json:"category"` Tags []string `json:"tags"` } // RecommendationCondition defines when a rule applies type RecommendationCondition struct { ScoreThreshold float64 `json:"score_threshold"` DimensionFilters map[string]float64 `json:"dimension_filters"` TrendConditions []string `json:"trend_conditions"` ContextFilters map[string]interface{} `json:"context_filters"` LogicalOperator string `json:"logical_operator"` // AND, OR } // RecommendationAction defines what to recommend type RecommendationAction struct { Type string `json:"type"` Description string `json:"description"` Impact float64 `json:"impact"` Effort float64 `json:"effort"` Timeline string `json:"timeline"` Resources []string `json:"resources"` Dependencies []string `json:"dependencies"` Metadata map[string]interface{} `json:"metadata"` } // MLRecommendationEngine provides ML-based recommendations type MLRecommendationEngine struct { models []RecommendationModel } // RecommendationModel interface for ML recommendation models type RecommendationModel interface { GenerateRecommendations(ctx context.Context, node *slurpContext.ContextNode, alignmentData *AlignmentAssessment) ([]*Recommendation, error) Train(data []*TrainingExample) error GetName() string GetConfidence() float64 } // TrainingExample represents training data for ML models type TrainingExample struct { Node *slurpContext.ContextNode `json:"node"` AlignmentBefore *AlignmentAssessment `json:"alignment_before"` AlignmentAfter *AlignmentAssessment `json:"alignment_after"` Actions []*RecommendationAction `json:"actions"` Outcome float64 `json:"outcome"` Timestamp time.Time `json:"timestamp"` } // RecommendationPrioritizer prioritizes recommendations type RecommendationPrioritizer struct { criteria []PrioritizationCriterion } // PrioritizationCriterion defines how to prioritize recommendations type PrioritizationCriterion struct { Name string `json:"name"` Weight float64 `json:"weight"` Calculator func(*Recommendation) float64 `json:"-"` } // AlignmentMetrics tracks alignment assessment metrics type AlignmentMetrics struct { mu sync.RWMutex totalAssessments int64 successfulAssessments int64 averageScore float64 scoreDistribution *ScoreDistribution dimensionPerformance map[string]*DimensionMetrics goalPerformance map[string]*GoalMetrics lastReset time.Time } // DimensionMetrics tracks metrics for a specific dimension type DimensionMetrics struct { TotalCalculations int64 `json:"total_calculations"` AverageScore float64 `json:"average_score"` Distribution *ScoreDistribution `json:"distribution"` FailureRate float64 `json:"failure_rate"` LastCalculated time.Time `json:"last_calculated"` } // GoalMetrics tracks metrics for a specific goal type GoalMetrics struct { TotalAssessments int64 `json:"total_assessments"` AverageAlignment float64 `json:"average_alignment"` TrendDirection string `json:"trend_direction"` LastAssessed time.Time `json:"last_assessed"` SuccessRate float64 `json:"success_rate"` } // AlignmentAssessment represents a complete alignment assessment type AlignmentAssessment struct { NodePath string `json:"node_path"` GoalID string `json:"goal_id"` OverallScore float64 `json:"overall_score"` Confidence float64 `json:"confidence"` DimensionScores []*DimensionScore `json:"dimension_scores"` Recommendations []*Recommendation `json:"recommendations"` Trends []*Trend `json:"trends"` Predictions []*AlignmentPrediction `json:"predictions"` Context map[string]interface{} `json:"context"` AssessedAt time.Time `json:"assessed_at"` AssessedBy string `json:"assessed_by"` Role string `json:"role"` Phase string `json:"phase"` } // Recommendation represents an alignment improvement recommendation type Recommendation struct { ID string `json:"id"` Title string `json:"title"` Description string `json:"description"` Action *RecommendationAction `json:"action"` Priority int `json:"priority"` Confidence float64 `json:"confidence"` Impact float64 `json:"impact"` Effort float64 `json:"effort"` Timeline string `json:"timeline"` Category string `json:"category"` Tags []string `json:"tags"` Dependencies []string `json:"dependencies"` Resources []string `json:"resources"` SuccessCriteria []string `json:"success_criteria"` RiskFactors []string `json:"risk_factors"` Alternatives []*Recommendation `json:"alternatives"` GeneratedAt time.Time `json:"generated_at"` GeneratedBy string `json:"generated_by"` } // NewGoalAlignmentEngine creates a new goal alignment engine func NewGoalAlignmentEngine(config *EngineConfig) *GoalAlignmentEngine { engine := &GoalAlignmentEngine{ config: config, scoringEngine: NewScoringEngine(config), dimensionAnalyzer: NewDimensionAnalyzer(), priorityCalculator: NewPriorityCalculator(), trendAnalyzer: NewTrendAnalyzer(), recommendationEngine: NewRecommendationEngine(), metrics: NewAlignmentMetrics(), } return engine } // NewScoringEngine creates a scoring engine func NewScoringEngine(config *EngineConfig) *ScoringEngine { engine := &ScoringEngine{ dimensions: []*ScoringDimension{}, weightConfig: NewWeightConfiguration(), normalizer: NewScoreNormalizer(), aggregator: NewScoreAggregator(), } // Initialize standard dimensions engine.initializeStandardDimensions() return engine } // AssessAlignment performs comprehensive goal alignment assessment func (gae *GoalAlignmentEngine) AssessAlignment(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal, role string) (*AlignmentAssessment, error) { start := time.Now() defer func() { gae.metrics.recordAssessment(time.Since(start)) }() // Calculate dimension scores dimensionScores, err := gae.calculateDimensionScores(ctx, node, goal) if err != nil { gae.metrics.recordFailure() return nil, fmt.Errorf("failed to calculate dimension scores: %w", err) } // Apply priority adjustments adjustedScores := gae.priorityCalculator.adjustScores(dimensionScores, goal, role) // Calculate overall score overallScore := gae.scoringEngine.aggregator.aggregate(adjustedScores, gae.scoringEngine.weightConfig) // Normalize scores normalizedScore := gae.scoringEngine.normalizer.normalize(overallScore, "overall") // Generate recommendations recommendations, err := gae.recommendationEngine.generateRecommendations(ctx, node, goal, adjustedScores) if err != nil { recommendations = []*Recommendation{} // Continue with empty recommendations } // Analyze trends trends := gae.trendAnalyzer.analyzeTrends(node.Path, goal.ID) // Generate predictions predictions, err := gae.trendAnalyzer.predictor.predictAlignment(ctx, node.Path, goal.ID, 30*24*time.Hour) if err != nil { predictions = []*AlignmentPrediction{} // Continue with empty predictions } // Calculate confidence confidence := gae.calculateOverallConfidence(adjustedScores) assessment := &AlignmentAssessment{ NodePath: node.Path, GoalID: goal.ID, OverallScore: normalizedScore, Confidence: confidence, DimensionScores: adjustedScores, Recommendations: recommendations, Trends: trends, Predictions: predictions, Context: map[string]interface{}{ "role": role, "goal_name": goal.Name, "phase": goal.Phase, }, AssessedAt: time.Now(), AssessedBy: "GoalAlignmentEngine", Role: role, Phase: goal.Phase, } // Record historical data gae.trendAnalyzer.recordAlignment(assessment) gae.metrics.recordSuccess(normalizedScore) return assessment, nil } // calculateDimensionScores calculates scores for all dimensions func (gae *GoalAlignmentEngine) calculateDimensionScores(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) ([]*DimensionScore, error) { scores := []*DimensionScore{} for _, dimension := range gae.scoringEngine.dimensions { score, err := dimension.Calculator.Calculate(ctx, node, goal) if err != nil { // Log error but continue with other dimensions continue } scores = append(scores, score) } if len(scores) == 0 { return nil, fmt.Errorf("no dimension scores calculated") } return scores, nil } // calculateOverallConfidence calculates overall confidence from dimension scores func (gae *GoalAlignmentEngine) calculateOverallConfidence(scores []*DimensionScore) float64 { if len(scores) == 0 { return 0.0 } totalConfidence := 0.0 for _, score := range scores { totalConfidence += score.Confidence } return totalConfidence / float64(len(scores)) } // Standard dimension calculators // KeywordAlignmentCalculator calculates alignment based on keyword matching type KeywordAlignmentCalculator struct { name string weight float64 } func NewKeywordAlignmentCalculator() *KeywordAlignmentCalculator { return &KeywordAlignmentCalculator{ name: "keyword_alignment", weight: 0.3, } } func (kac *KeywordAlignmentCalculator) GetName() string { return kac.name } func (kac *KeywordAlignmentCalculator) GetWeight() float64 { return kac.weight } func (kac *KeywordAlignmentCalculator) Validate(node *slurpContext.ContextNode, goal *ProjectGoal) error { if node == nil || goal == nil { return fmt.Errorf("node and goal cannot be nil") } return nil } func (kac *KeywordAlignmentCalculator) Calculate(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) (*DimensionScore, error) { if err := kac.Validate(node, goal); err != nil { return nil, err } // Combine node text for analysis nodeText := strings.ToLower(node.Summary + " " + node.Purpose + " " + strings.Join(node.Technologies, " ") + " " + strings.Join(node.Tags, " ")) // Calculate keyword matches matches := 0 evidence := []string{} for _, keyword := range goal.Keywords { if strings.Contains(nodeText, strings.ToLower(keyword)) { matches++ evidence = append(evidence, fmt.Sprintf("Found keyword: %s", keyword)) } } // Calculate score score := 0.0 if len(goal.Keywords) > 0 { score = float64(matches) / float64(len(goal.Keywords)) } // Calculate confidence based on evidence strength confidence := math.Min(0.9, float64(matches)*0.2+0.1) return &DimensionScore{ Dimension: kac.name, Score: score, Confidence: confidence, Evidence: evidence, Reasoning: fmt.Sprintf("Found %d out of %d keywords", matches, len(goal.Keywords)), SubScores: map[string]float64{"keyword_matches": float64(matches)}, CalculatedAt: time.Now(), }, nil } // TechnologyAlignmentCalculator calculates alignment based on technology stack type TechnologyAlignmentCalculator struct { name string weight float64 } func NewTechnologyAlignmentCalculator() *TechnologyAlignmentCalculator { return &TechnologyAlignmentCalculator{ name: "technology_alignment", weight: 0.25, } } func (tac *TechnologyAlignmentCalculator) GetName() string { return tac.name } func (tac *TechnologyAlignmentCalculator) GetWeight() float64 { return tac.weight } func (tac *TechnologyAlignmentCalculator) Validate(node *slurpContext.ContextNode, goal *ProjectGoal) error { if node == nil || goal == nil { return fmt.Errorf("node and goal cannot be nil") } return nil } func (tac *TechnologyAlignmentCalculator) Calculate(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) (*DimensionScore, error) { if err := tac.Validate(node, goal); err != nil { return nil, err } // Check if goal keywords include technology-related terms techKeywords := []string{} for _, keyword := range goal.Keywords { if tac.isTechnologyKeyword(keyword) { techKeywords = append(techKeywords, keyword) } } if len(techKeywords) == 0 { // If no tech keywords in goal, score based on general technology presence score := 0.5 if len(node.Technologies) > 0 { score = 0.7 } return &DimensionScore{ Dimension: tac.name, Score: score, Confidence: 0.5, Evidence: []string{"No specific technology requirements in goal"}, Reasoning: "General technology assessment", CalculatedAt: time.Now(), }, nil } // Calculate technology alignment matches := 0 evidence := []string{} for _, tech := range node.Technologies { for _, keyword := range techKeywords { if strings.Contains(strings.ToLower(tech), strings.ToLower(keyword)) || strings.Contains(strings.ToLower(keyword), strings.ToLower(tech)) { matches++ evidence = append(evidence, fmt.Sprintf("Technology match: %s ~ %s", tech, keyword)) } } } score := 0.0 if len(techKeywords) > 0 { score = float64(matches) / float64(len(techKeywords)) } confidence := math.Min(0.9, float64(matches)*0.3+0.2) return &DimensionScore{ Dimension: tac.name, Score: score, Confidence: confidence, Evidence: evidence, Reasoning: fmt.Sprintf("Technology alignment: %d matches out of %d tech keywords", matches, len(techKeywords)), SubScores: map[string]float64{"tech_matches": float64(matches)}, CalculatedAt: time.Now(), }, nil } func (tac *TechnologyAlignmentCalculator) isTechnologyKeyword(keyword string) bool { techTerms := []string{ "go", "golang", "python", "javascript", "typescript", "java", "rust", "c++", "c#", "react", "vue", "angular", "node", "express", "django", "flask", "spring", "docker", "kubernetes", "aws", "azure", "gcp", "terraform", "ansible", "mysql", "postgresql", "mongodb", "redis", "elasticsearch", "microservices", "api", "rest", "graphql", "grpc", "websocket", } lowerKeyword := strings.ToLower(keyword) for _, term := range techTerms { if strings.Contains(lowerKeyword, term) { return true } } return false } // Initialize scoring engine with standard dimensions func (se *ScoringEngine) initializeStandardDimensions() { dimensions := []*ScoringDimension{ { Name: "keyword_alignment", Description: "Alignment based on keyword matching", Weight: 0.3, Calculator: NewKeywordAlignmentCalculator(), Threshold: 0.3, Priority: 1, Category: "content", }, { Name: "technology_alignment", Description: "Alignment based on technology stack", Weight: 0.25, Calculator: NewTechnologyAlignmentCalculator(), Threshold: 0.2, Priority: 2, Category: "technical", }, { Name: "purpose_alignment", Description: "Alignment based on stated purpose", Weight: 0.2, Calculator: NewPurposeAlignmentCalculator(), Threshold: 0.25, Priority: 1, Category: "functional", }, { Name: "phase_alignment", Description: "Alignment with project phase", Weight: 0.15, Calculator: NewPhaseAlignmentCalculator(), Threshold: 0.3, Priority: 3, Category: "temporal", }, { Name: "context_relevance", Description: "Overall context relevance", Weight: 0.1, Calculator: NewContextRelevanceCalculator(), Threshold: 0.2, Priority: 4, Category: "contextual", }, } se.dimensions = dimensions } // Additional calculator implementations would follow similar patterns... // PurposeAlignmentCalculator calculates alignment based on stated purpose type PurposeAlignmentCalculator struct { name string weight float64 } func NewPurposeAlignmentCalculator() *PurposeAlignmentCalculator { return &PurposeAlignmentCalculator{ name: "purpose_alignment", weight: 0.2, } } func (pac *PurposeAlignmentCalculator) GetName() string { return pac.name } func (pac *PurposeAlignmentCalculator) GetWeight() float64 { return pac.weight } func (pac *PurposeAlignmentCalculator) Validate(node *slurpContext.ContextNode, goal *ProjectGoal) error { if node == nil || goal == nil { return fmt.Errorf("node and goal cannot be nil") } return nil } func (pac *PurposeAlignmentCalculator) Calculate(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) (*DimensionScore, error) { // Semantic similarity between node purpose and goal description purposeAlignment := pac.calculateSemanticSimilarity(node.Purpose, goal.Description) return &DimensionScore{ Dimension: pac.name, Score: purposeAlignment, Confidence: 0.7, Evidence: []string{fmt.Sprintf("Purpose: %s", node.Purpose)}, Reasoning: "Semantic similarity between purpose and goal description", CalculatedAt: time.Now(), }, nil } func (pac *PurposeAlignmentCalculator) calculateSemanticSimilarity(purpose, description string) float64 { // Simple implementation - in production would use more sophisticated NLP purposeWords := strings.Fields(strings.ToLower(purpose)) descWords := strings.Fields(strings.ToLower(description)) matches := 0 for _, pWord := range purposeWords { for _, dWord := range descWords { if pWord == dWord || strings.Contains(pWord, dWord) || strings.Contains(dWord, pWord) { matches++ break } } } if len(purposeWords) == 0 { return 0.0 } return float64(matches) / float64(len(purposeWords)) } // PhaseAlignmentCalculator calculates alignment with project phase type PhaseAlignmentCalculator struct { name string weight float64 } func NewPhaseAlignmentCalculator() *PhaseAlignmentCalculator { return &PhaseAlignmentCalculator{ name: "phase_alignment", weight: 0.15, } } func (phac *PhaseAlignmentCalculator) GetName() string { return phac.name } func (phac *PhaseAlignmentCalculator) GetWeight() float64 { return phac.weight } func (phac *PhaseAlignmentCalculator) Validate(node *slurpContext.ContextNode, goal *ProjectGoal) error { return nil } func (phac *PhaseAlignmentCalculator) Calculate(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) (*DimensionScore, error) { // Phase alignment logic phaseScore := phac.calculatePhaseRelevance(node, goal.Phase) return &DimensionScore{ Dimension: phac.name, Score: phaseScore, Confidence: 0.8, Evidence: []string{fmt.Sprintf("Goal phase: %s", goal.Phase)}, Reasoning: "Alignment with current project phase", CalculatedAt: time.Now(), }, nil } func (phac *PhaseAlignmentCalculator) calculatePhaseRelevance(node *slurpContext.ContextNode, phase string) float64 { // Simple phase relevance calculation phaseRelevance := map[string]map[string]float64{ "planning": { "documentation": 0.9, "architecture": 0.8, "research": 0.9, "design": 0.8, }, "development": { "implementation": 0.9, "testing": 0.7, "coding": 0.9, "api": 0.8, }, "testing": { "testing": 0.9, "quality": 0.8, "validation": 0.9, "bug": 0.7, }, "deployment": { "deployment": 0.9, "infrastructure": 0.8, "monitoring": 0.8, "production": 0.9, }, } nodeText := strings.ToLower(node.Purpose + " " + node.Summary) relevanceMap, exists := phaseRelevance[strings.ToLower(phase)] if !exists { return 0.5 // Default relevance } maxRelevance := 0.0 for keyword, score := range relevanceMap { if strings.Contains(nodeText, keyword) { if score > maxRelevance { maxRelevance = score } } } if maxRelevance == 0.0 { return 0.4 // Default when no specific phase keywords found } return maxRelevance } // ContextRelevanceCalculator calculates overall context relevance type ContextRelevanceCalculator struct { name string weight float64 } func NewContextRelevanceCalculator() *ContextRelevanceCalculator { return &ContextRelevanceCalculator{ name: "context_relevance", weight: 0.1, } } func (crc *ContextRelevanceCalculator) GetName() string { return crc.name } func (crc *ContextRelevanceCalculator) GetWeight() float64 { return crc.weight } func (crc *ContextRelevanceCalculator) Validate(node *slurpContext.ContextNode, goal *ProjectGoal) error { return nil } func (crc *ContextRelevanceCalculator) Calculate(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal) (*DimensionScore, error) { // Calculate overall context relevance relevanceScore := crc.calculateRelevance(node, goal) return &DimensionScore{ Dimension: crc.name, Score: relevanceScore, Confidence: 0.6, Evidence: []string{"Overall context assessment"}, Reasoning: "Calculated based on multiple context factors", CalculatedAt: time.Now(), }, nil } func (crc *ContextRelevanceCalculator) calculateRelevance(node *slurpContext.ContextNode, goal *ProjectGoal) float64 { // Combine multiple factors for overall relevance factors := []float64{} // Factor 1: Specificity vs Goal Priority specificityFactor := float64(node.ContextSpecificity) / 10.0 * (1.0 / float64(goal.Priority)) factors = append(factors, specificityFactor) // Factor 2: RAG Confidence factors = append(factors, node.RAGConfidence) // Factor 3: Technology richness techFactor := math.Min(1.0, float64(len(node.Technologies))/3.0) factors = append(factors, techFactor) // Factor 4: Insight richness insightFactor := math.Min(1.0, float64(len(node.Insights))/5.0) factors = append(factors, insightFactor) // Calculate weighted average totalWeight := 0.0 weightedSum := 0.0 weights := []float64{0.4, 0.3, 0.2, 0.1} for i, factor := range factors { if i < len(weights) { weightedSum += factor * weights[i] totalWeight += weights[i] } } if totalWeight == 0.0 { return 0.5 } return weightedSum / totalWeight } // Helper methods for scoring engine components func NewWeightConfiguration() *WeightConfiguration { return &WeightConfiguration{ GlobalWeights: make(map[string]float64), RoleWeights: make(map[string]map[string]float64), PhaseWeights: make(map[string]map[string]float64), ProjectWeights: make(map[string]map[string]float64), DynamicWeights: true, LastUpdated: time.Now(), } } func NewScoreNormalizer() *ScoreNormalizer { return &ScoreNormalizer{ normalizationMethod: "z_score", referenceData: &NormalizationReference{ HistoricalScores: make(map[string]*ScoreDistribution), Percentiles: make(map[string]map[int]float64), LastCalculated: time.Now(), }, } } func NewScoreAggregator() *ScoreAggregator { return &ScoreAggregator{ method: "weighted_average", } } func (sa *ScoreAggregator) aggregate(scores []*DimensionScore, weights *WeightConfiguration) float64 { if len(scores) == 0 { return 0.0 } totalWeight := 0.0 weightedSum := 0.0 for _, score := range scores { weight := 1.0 // Default weight if globalWeight, exists := weights.GlobalWeights[score.Dimension]; exists { weight = globalWeight } weightedSum += score.Score * weight totalWeight += weight } if totalWeight == 0.0 { return 0.0 } return weightedSum / totalWeight } func (sn *ScoreNormalizer) normalize(score float64, dimension string) float64 { // Simple normalization - in production would use more sophisticated methods return math.Max(0.0, math.Min(1.0, score)) } // Create remaining component constructors... func NewDimensionAnalyzer() *DimensionAnalyzer { return &DimensionAnalyzer{ calculators: make(map[string]DimensionCalculator), } } func NewPriorityCalculator() *PriorityCalculator { return &PriorityCalculator{ priorityMatrix: &PriorityMatrix{ Goals: make(map[string]int), Phases: make(map[string]int), Technologies: make(map[string]int), Roles: make(map[string]int), Urgency: make(map[string]float64), Impact: make(map[string]float64), }, timeFactors: &TimeFactors{ DecayFunction: "exponential", HalfLife: 30 * 24 * time.Hour, UrgencyBoost: 1.5, DeadlineWeight: 2.0, PhaseAlignment: make(map[string]float64), }, } } func (pc *PriorityCalculator) adjustScores(scores []*DimensionScore, goal *ProjectGoal, role string) []*DimensionScore { adjusted := make([]*DimensionScore, len(scores)) for i, score := range scores { adjustedScore := *score // Copy the score // Apply priority adjustments priorityMultiplier := pc.calculatePriorityMultiplier(goal, role) adjustedScore.Score *= priorityMultiplier // Apply time-based adjustments timeMultiplier := pc.calculateTimeMultiplier(goal) adjustedScore.Score *= timeMultiplier // Ensure score stays within bounds adjustedScore.Score = math.Max(0.0, math.Min(1.0, adjustedScore.Score)) adjusted[i] = &adjustedScore } return adjusted } func (pc *PriorityCalculator) calculatePriorityMultiplier(goal *ProjectGoal, role string) float64 { // Base multiplier from goal priority (inverse - higher priority = higher multiplier) priorityMultiplier := 1.0 + (1.0 / float64(goal.Priority)) // Role-specific adjustments if roleMultiplier, exists := pc.priorityMatrix.Urgency[role]; exists { priorityMultiplier *= roleMultiplier } return priorityMultiplier } func (pc *PriorityCalculator) calculateTimeMultiplier(goal *ProjectGoal) float64 { if goal.Deadline == nil { return 1.0 } // Calculate urgency based on deadline proximity timeToDeadline := time.Until(*goal.Deadline) if timeToDeadline <= 0 { return pc.timeFactors.UrgencyBoost // Past deadline } // Exponential urgency increase as deadline approaches urgencyFactor := math.Exp(-float64(timeToDeadline) / float64(pc.timeFactors.HalfLife)) return 1.0 + urgencyFactor*pc.timeFactors.DeadlineWeight } func NewTrendAnalyzer() *TrendAnalyzer { return &TrendAnalyzer{ historicalData: &AlignmentHistory{ records: []*AlignmentRecord{}, maxRecords: 10000, retention: 90 * 24 * time.Hour, }, trendDetector: &TrendDetector{ methods: []TrendDetectionMethod{}, }, predictor: &AlignmentPredictor{ models: []PredictionModel{}, }, } } func (ta *TrendAnalyzer) analyzeTrends(nodePath, goalID string) []*Trend { // Simple trend analysis - in production would be more sophisticated return []*Trend{} } func (ta *TrendAnalyzer) recordAlignment(assessment *AlignmentAssessment) { record := &AlignmentRecord{ NodePath: assessment.NodePath, GoalID: assessment.GoalID, Score: assessment.OverallScore, Dimensions: assessment.DimensionScores, Context: assessment.Context, Timestamp: assessment.AssessedAt, Role: assessment.Role, Phase: assessment.Phase, } ta.historicalData.mu.Lock() ta.historicalData.records = append(ta.historicalData.records, record) // Trim old records if necessary if len(ta.historicalData.records) > ta.historicalData.maxRecords { ta.historicalData.records = ta.historicalData.records[1:] } ta.historicalData.mu.Unlock() } func (ap *AlignmentPredictor) predictAlignment(ctx context.Context, nodePath, goalID string, horizon time.Duration) ([]*AlignmentPrediction, error) { // Simple prediction - in production would use ML models return []*AlignmentPrediction{}, nil } func NewRecommendationEngine() *RecommendationEngine { return &RecommendationEngine{ ruleEngine: NewRecommendationRuleEngine(), mlEngine: NewMLRecommendationEngine(), prioritizer: NewRecommendationPrioritizer(), } } func (re *RecommendationEngine) generateRecommendations(ctx context.Context, node *slurpContext.ContextNode, goal *ProjectGoal, scores []*DimensionScore) ([]*Recommendation, error) { recommendations := []*Recommendation{} // Generate rule-based recommendations ruleRecs, err := re.ruleEngine.generateRecommendations(scores) if err == nil { recommendations = append(recommendations, ruleRecs...) } // Generate ML-based recommendations (if available) // mlRecs, err := re.mlEngine.generateRecommendations(ctx, node, scores) // if err == nil { // recommendations = append(recommendations, mlRecs...) // } // Prioritize recommendations prioritized := re.prioritizer.prioritize(recommendations) return prioritized, nil } func NewRecommendationRuleEngine() *RecommendationRuleEngine { engine := &RecommendationRuleEngine{ rules: []*RecommendationRule{}, } engine.loadDefaultRules() return engine } func (rre *RecommendationRuleEngine) loadDefaultRules() { rules := []*RecommendationRule{ { ID: "low_keyword_alignment", Name: "Improve Keyword Alignment", Condition: RecommendationCondition{ DimensionFilters: map[string]float64{"keyword_alignment": 0.3}, LogicalOperator: "LT", }, Action: RecommendationAction{ Type: "content_enhancement", Description: "Add more relevant keywords to improve alignment with project goals", Impact: 0.7, Effort: 0.3, Timeline: "short", Resources: []string{"documentation", "content_review"}, }, Priority: 1, Confidence: 0.8, Category: "content", }, { ID: "technology_mismatch", Name: "Address Technology Mismatch", Condition: RecommendationCondition{ DimensionFilters: map[string]float64{"technology_alignment": 0.2}, LogicalOperator: "LT", }, Action: RecommendationAction{ Type: "technology_update", Description: "Update technology stack or documentation to better align with project goals", Impact: 0.8, Effort: 0.6, Timeline: "medium", Resources: []string{"development", "architecture_review"}, }, Priority: 2, Confidence: 0.7, Category: "technical", }, } rre.rules = rules } func (rre *RecommendationRuleEngine) generateRecommendations(scores []*DimensionScore) ([]*Recommendation, error) { recommendations := []*Recommendation{} for _, rule := range rre.rules { if rre.evaluateCondition(rule.Condition, scores) { rec := &Recommendation{ ID: rule.ID, Title: rule.Name, Description: rule.Action.Description, Action: &rule.Action, Priority: rule.Priority, Confidence: rule.Confidence, Impact: rule.Action.Impact, Effort: rule.Action.Effort, Timeline: rule.Action.Timeline, Category: rule.Category, Resources: rule.Action.Resources, GeneratedAt: time.Now(), GeneratedBy: "RuleEngine", } recommendations = append(recommendations, rec) } } return recommendations, nil } func (rre *RecommendationRuleEngine) evaluateCondition(condition RecommendationCondition, scores []*DimensionScore) bool { for dimension, threshold := range condition.DimensionFilters { for _, score := range scores { if score.Dimension == dimension { switch condition.LogicalOperator { case "LT": return score.Score < threshold case "GT": return score.Score > threshold case "EQ": return math.Abs(score.Score-threshold) < 0.01 default: return score.Score < threshold } } } } return false } func NewMLRecommendationEngine() *MLRecommendationEngine { return &MLRecommendationEngine{ models: []RecommendationModel{}, } } func NewRecommendationPrioritizer() *RecommendationPrioritizer { return &RecommendationPrioritizer{ criteria: []PrioritizationCriterion{ { Name: "impact_effort_ratio", Weight: 0.4, Calculator: func(rec *Recommendation) float64 { if rec.Effort == 0 { return rec.Impact } return rec.Impact / rec.Effort }, }, { Name: "confidence", Weight: 0.3, Calculator: func(rec *Recommendation) float64 { return rec.Confidence }, }, { Name: "priority", Weight: 0.3, Calculator: func(rec *Recommendation) float64 { return 1.0 / float64(rec.Priority) // Inverse priority }, }, }, } } func (rp *RecommendationPrioritizer) prioritize(recommendations []*Recommendation) []*Recommendation { // Calculate priority scores for each recommendation for _, rec := range recommendations { score := 0.0 totalWeight := 0.0 for _, criterion := range rp.criteria { criterionScore := criterion.Calculator(rec) score += criterionScore * criterion.Weight totalWeight += criterion.Weight } if totalWeight > 0 { rec.Priority = int((score / totalWeight) * 100) // Convert to 0-100 scale } } // Sort by priority score (higher is better) sort.Slice(recommendations, func(i, j int) bool { return recommendations[i].Priority > recommendations[j].Priority }) return recommendations } func NewAlignmentMetrics() *AlignmentMetrics { return &AlignmentMetrics{ dimensionPerformance: make(map[string]*DimensionMetrics), goalPerformance: make(map[string]*GoalMetrics), lastReset: time.Now(), } } func (am *AlignmentMetrics) recordAssessment(duration time.Duration) { am.mu.Lock() defer am.mu.Unlock() am.totalAssessments++ } func (am *AlignmentMetrics) recordSuccess(score float64) { am.mu.Lock() defer am.mu.Unlock() am.successfulAssessments++ // Update average score if am.totalAssessments == 1 { am.averageScore = score } else { am.averageScore = (am.averageScore*float64(am.totalAssessments-1) + score) / float64(am.totalAssessments) } } func (am *AlignmentMetrics) recordFailure() { am.mu.Lock() defer am.mu.Unlock() // Failure count is totalAssessments - successfulAssessments } func (am *AlignmentMetrics) GetMetrics() map[string]interface{} { am.mu.RLock() defer am.mu.RUnlock() successRate := 0.0 if am.totalAssessments > 0 { successRate = float64(am.successfulAssessments) / float64(am.totalAssessments) } return map[string]interface{}{ "total_assessments": am.totalAssessments, "successful_assessments": am.successfulAssessments, "success_rate": successRate, "average_score": am.averageScore, "last_reset": am.lastReset, } }