| 207 | } |
| 208 | |
| 209 | func scoreAuditComparisonCandidate(current ProcessedRun, candidate *auditComparisonCandidate) { |
| 210 | if candidate == nil { |
| 211 | return |
| 212 | } |
| 213 | auditComparisonLog.Printf("Scoring baseline candidate: run_id=%d", candidate.Run.DatabaseID) |
| 214 | |
| 215 | score := 0 |
| 216 | matchedOn := make([]string, 0, 6) |
| 217 | |
| 218 | if current.Run.Event != "" && current.Run.Event == candidate.Run.Event { |
| 219 | score += 5 |
| 220 | matchedOn = append(matchedOn, "event") |
| 221 | } |
| 222 | |
| 223 | if current.TaskDomain != nil && candidate.TaskDomain != nil && current.TaskDomain.Name == candidate.TaskDomain.Name { |
| 224 | score += 50 |
| 225 | matchedOn = append(matchedOn, "task_domain") |
| 226 | } |
| 227 | |
| 228 | if current.BehaviorFingerprint != nil && candidate.BehaviorFingerprint != nil { |
| 229 | if current.BehaviorFingerprint.ExecutionStyle == candidate.BehaviorFingerprint.ExecutionStyle { |
| 230 | score += 20 |
| 231 | matchedOn = append(matchedOn, "execution_style") |
| 232 | } |
| 233 | if current.BehaviorFingerprint.ResourceProfile == candidate.BehaviorFingerprint.ResourceProfile { |
| 234 | score += 25 |
| 235 | matchedOn = append(matchedOn, "resource_profile") |
| 236 | } |
| 237 | if current.BehaviorFingerprint.ActuationStyle == candidate.BehaviorFingerprint.ActuationStyle { |
| 238 | score += 10 |
| 239 | matchedOn = append(matchedOn, "actuation_style") |
| 240 | } |
| 241 | if current.BehaviorFingerprint.DispatchMode == candidate.BehaviorFingerprint.DispatchMode { |
| 242 | score += 5 |
| 243 | matchedOn = append(matchedOn, "dispatch_mode") |
| 244 | } |
| 245 | if current.BehaviorFingerprint.ToolBreadth == candidate.BehaviorFingerprint.ToolBreadth { |
| 246 | score += 2 |
| 247 | matchedOn = append(matchedOn, "tool_breadth") |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | candidate.Score = score |
| 252 | if slices.Contains(matchedOn, "task_domain") || slices.Contains(matchedOn, "execution_style") || slices.Contains(matchedOn, "resource_profile") || slices.Contains(matchedOn, "actuation_style") { |
| 253 | candidate.Selection = "cohort_match" |
| 254 | candidate.MatchedOn = matchedOn |
| 255 | auditComparisonLog.Printf("Candidate %d classified as cohort_match: score=%d, matched=%v", candidate.Run.DatabaseID, score, matchedOn) |
| 256 | return |
| 257 | } |
| 258 | |
| 259 | candidate.Selection = "latest_success" |
| 260 | candidate.MatchedOn = nil |
| 261 | auditComparisonLog.Printf("Candidate %d classified as latest_success: score=%d", candidate.Run.DatabaseID, score) |
| 262 | } |
| 263 | |
| 264 | func selectAuditComparisonBaseline(current ProcessedRun, candidates []auditComparisonCandidate) *auditComparisonCandidate { |
| 265 | auditComparisonLog.Printf("Selecting baseline from %d candidates for run %d", len(candidates), current.Run.DatabaseID) |