code_healer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +70 -0
  3. data/GEM_SUMMARY.md +307 -0
  4. data/README.md +281 -0
  5. data/code_healer.gemspec +77 -0
  6. data/config/code_healer.yml.example +104 -0
  7. data/docs/INSTALLATION.md +439 -0
  8. data/examples/basic_usage.rb +160 -0
  9. data/exe/code_healer-setup +7 -0
  10. data/lib/code_healer/application_job.rb +7 -0
  11. data/lib/code_healer/business_context_analyzer.rb +464 -0
  12. data/lib/code_healer/business_context_loader.rb +273 -0
  13. data/lib/code_healer/business_context_manager.rb +297 -0
  14. data/lib/code_healer/business_logic_generator.rb +94 -0
  15. data/lib/code_healer/business_rule_applier.rb +54 -0
  16. data/lib/code_healer/claude_code_evolution_handler.rb +224 -0
  17. data/lib/code_healer/claude_error_monitor.rb +48 -0
  18. data/lib/code_healer/config_manager.rb +275 -0
  19. data/lib/code_healer/context_aware_prompt_builder.rb +153 -0
  20. data/lib/code_healer/core.rb +513 -0
  21. data/lib/code_healer/error_handler.rb +141 -0
  22. data/lib/code_healer/evolution_job.rb +99 -0
  23. data/lib/code_healer/global_handler.rb +130 -0
  24. data/lib/code_healer/healing_job.rb +167 -0
  25. data/lib/code_healer/mcp.rb +108 -0
  26. data/lib/code_healer/mcp_prompts.rb +111 -0
  27. data/lib/code_healer/mcp_server.rb +389 -0
  28. data/lib/code_healer/mcp_tools.rb +2364 -0
  29. data/lib/code_healer/pull_request_creator.rb +143 -0
  30. data/lib/code_healer/setup.rb +390 -0
  31. data/lib/code_healer/simple_evolution.rb +737 -0
  32. data/lib/code_healer/simple_global_handler.rb +122 -0
  33. data/lib/code_healer/simple_healer.rb +515 -0
  34. data/lib/code_healer/terminal_integration.rb +87 -0
  35. data/lib/code_healer/usage_analyzer.rb +92 -0
  36. data/lib/code_healer/version.rb +5 -0
  37. data/lib/code_healer.rb +67 -0
  38. metadata +411 -0
@@ -0,0 +1,160 @@
1
+ # Basic Usage Example
2
+ # This example shows how to use CodeHealer in a simple Rails application
3
+
4
+ # 1. Add to Gemfile
5
+ puts "Add to your Gemfile:"
6
+ puts "gem 'code_healer'"
7
+ puts
8
+
9
+ # 2. Configuration
10
+ puts "Create config/code_healer.yml:"
11
+ puts <<~YAML
12
+ ---
13
+ enabled: true
14
+
15
+ allowed_classes:
16
+ - User
17
+ - Order
18
+ - PaymentProcessor
19
+
20
+ evolution_strategy:
21
+ method: "api"
22
+
23
+ business_context:
24
+ enabled: true
25
+ User:
26
+ domain: "User Management"
27
+ key_rules:
28
+ - "Email must be unique and valid"
29
+ - "Password must meet security requirements"
30
+ YAML
31
+ puts
32
+
33
+ # 3. Model Example
34
+ puts "Example model (app/models/user.rb):"
35
+ puts <<~RUBY
36
+ class User < ApplicationRecord
37
+ def calculate_discount(amount, percentage)
38
+ # This will trigger evolution if an error occurs
39
+ amount * (percentage / 100.0)
40
+ end
41
+
42
+ def validate_payment(card_number, expiry_date)
43
+ # Another method that can evolve
44
+ card_number.length == 16 && expiry_date > Date.current
45
+ end
46
+ end
47
+ RUBY
48
+ puts
49
+
50
+ # 4. Controller Example
51
+ puts "Example controller (app/controllers/api/users_controller.rb):"
52
+ puts <<~RUBY
53
+ class Api::UsersController < ApplicationController
54
+ def calculate_discount
55
+ user = User.find(params[:id])
56
+ discount = user.calculate_discount(
57
+ params[:amount].to_f,
58
+ params[:percentage].to_f
59
+ )
60
+
61
+ render json: { discount: discount }
62
+ rescue => e
63
+ # CodeHealer will catch this error and fix it
64
+ render json: { error: e.message }, status: 500
65
+ end
66
+ end
67
+ RUBY
68
+ puts
69
+
70
+ # 5. Routes
71
+ puts "Add to config/routes.rb:"
72
+ puts <<~RUBY
73
+ Rails.application.routes.draw do
74
+ namespace :api do
75
+ resources :users do
76
+ member do
77
+ post :calculate_discount
78
+ end
79
+ end
80
+ end
81
+ end
82
+ RUBY
83
+ puts
84
+
85
+ # 6. Test the Evolution
86
+ puts "Test the evolution:"
87
+ puts <<~BASH
88
+ # Start your Rails server
89
+ rails server
90
+
91
+ # In another terminal, trigger an error
92
+ curl -X POST http://localhost:3000/api/users/1/calculate_discount \\
93
+ -H "Content-Type: application/json" \\
94
+ -d '{"amount": 100, "percentage": nil}'
95
+ BASH
96
+ puts
97
+
98
+ # 7. Watch the Evolution
99
+ puts "Watch the healing in action:"
100
+ puts <<~BASH
101
+ # Check Rails logs
102
+ tail -f log/development.log
103
+
104
+ # Check Sidekiq (if using background jobs)
105
+ tail -f log/sidekiq.log
106
+
107
+ # Monitor Sidekiq Web UI
108
+ open http://localhost:3000/sidekiq
109
+ BASH
110
+ puts
111
+
112
+ # 8. Business Requirements
113
+ puts "Create business_requirements/user_management.md:"
114
+ puts <<~MARKDOWN
115
+ # User Management Business Rules
116
+
117
+ ## Authentication
118
+ - Users must have valid email addresses
119
+ - Passwords must be at least 8 characters
120
+ - Failed login attempts should be logged
121
+
122
+ ## Discount Calculation
123
+ - Discount cannot exceed 50% of total amount
124
+ - Negative percentages are not allowed
125
+ - Zero amounts should return zero discount
126
+
127
+ ## Data Validation
128
+ - All user input must be sanitized
129
+ - Email uniqueness is enforced at database level
130
+ MARKDOWN
131
+ puts
132
+
133
+ # 9. Environment Variables
134
+ puts "Set environment variables (.env):"
135
+ puts <<~ENV
136
+ OPENAI_API_KEY=your_openai_api_key_here
137
+ GITHUB_TOKEN=your_github_token_here
138
+ ENV
139
+ puts
140
+
141
+ # 10. Sidekiq Configuration
142
+ puts "Create config/sidekiq.yml:"
143
+ puts <<~YAML
144
+ :concurrency: 5
145
+ :queues:
146
+ - [evolution, 2]
147
+ - [default, 1]
148
+ YAML
149
+ puts
150
+
151
+ puts "🎉 Your CodeHealer application is ready!"
152
+ puts
153
+ puts "Next steps:"
154
+ puts "1. Run 'bundle install'"
155
+ puts "2. Start Redis: 'redis-server'"
156
+ puts "3. Start Sidekiq: 'bundle exec sidekiq'"
157
+ puts "4. Start Rails: 'rails server'"
158
+ puts "5. Test with the curl command above"
159
+ puts
160
+ puts "Watch the magic happen! 🚀"
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # This executable provides the code_healer-setup command
5
+ # It loads the setup script from the gem's lib directory
6
+
7
+ require_relative '../lib/code_healer/setup'
@@ -0,0 +1,7 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ # Automatically retry jobs that encountered a deadlock
3
+ # retry_on ActiveRecord::Deadlocked
4
+
5
+ # Most jobs are safe to ignore if the underlying records are no longer available
6
+ # discard_on ActiveJob::DeserializationError
7
+ end
@@ -0,0 +1,464 @@
1
+ module CodeHealer
2
+ # Business Context Analyzer
3
+ # Reads business context from files and applies business rules before evolution
4
+ # Works like a developer analyzing business requirements before fixing bugs
5
+ class BusinessContextAnalyzer
6
+ class << self
7
+
8
+ def analyze_error_for_business_context(error, class_name, method_name, file_path)
9
+ puts "🔍 DEBUG: analyze_error_for_business_context called with:"
10
+ puts " - error: #{error.class} (#{error.message})"
11
+ puts " - class_name: #{class_name.inspect}"
12
+ puts " - method_name: #{method_name.inspect}"
13
+ puts " - file_path: #{file_path.inspect}"
14
+
15
+ puts "🔍 Analyzing business context for #{class_name}##{method_name} error..."
16
+
17
+ # Load business context from various sources
18
+ puts " 🔍 DEBUG: About to call load_business_context..."
19
+ business_context = load_business_context(file_path, class_name, method_name)
20
+ puts " 🔍 DEBUG: load_business_context returned: #{business_context.keys}"
21
+
22
+ # Analyze the error against business rules
23
+ puts " 🔍 DEBUG: About to call analyze_error_against_business_rules..."
24
+ analysis_result = analyze_error_against_business_rules(error, business_context, class_name, method_name)
25
+ puts " 🔍 DEBUG: analyze_error_against_business_rules returned: #{analysis_result.keys}"
26
+
27
+ # Determine evolution strategy based on business context
28
+ puts " 🔍 DEBUG: About to call determine_evolution_strategy..."
29
+ evolution_strategy = determine_evolution_strategy(analysis_result, error, class_name, method_name)
30
+ puts " 🔍 DEBUG: determine_evolution_strategy returned: #{evolution_strategy.keys}"
31
+
32
+ puts " 📋 Business context analysis complete"
33
+ puts " 🎯 Evolution strategy: #{evolution_strategy[:strategy]}"
34
+ puts " 💼 Business impact: #{evolution_strategy[:business_impact]}"
35
+
36
+ {
37
+ business_context: business_context,
38
+ analysis: analysis_result,
39
+ evolution_strategy: evolution_strategy
40
+ }
41
+ end
42
+
43
+ private
44
+
45
+ def load_business_context(file_path, class_name, method_name)
46
+ puts " 🔍 DEBUG: load_business_context called with:"
47
+ puts " - file_path: #{file_path.inspect}"
48
+ puts " - class_name: #{class_name.inspect}"
49
+ puts " - method_name: #{method_name.inspect}"
50
+
51
+ puts " 🔍 DEBUG: About to call load_requirements_documents..."
52
+ requirements = load_requirements_documents(file_path, class_name, method_name)
53
+ puts " 🔍 DEBUG: load_requirements_documents returned #{requirements.length} documents"
54
+
55
+ puts " 🔍 DEBUG: About to call load_business_rules_documents..."
56
+ business_rules = load_business_rules_documents(file_path, class_name, method_name)
57
+ puts " 🔍 DEBUG: load_business_rules_documents returned #{business_rules.length} documents"
58
+
59
+ puts " 🔍 DEBUG: About to call load_error_handling_documents..."
60
+ error_handling = load_error_handling_documents(file_path, class_name, method_name)
61
+ puts " 🔍 DEBUG: load_error_handling_documents returned #{error_handling.length} documents"
62
+
63
+ puts " 🔍 DEBUG: About to call load_user_experience_documents..."
64
+ user_experience = load_user_experience_documents(file_path, class_name, method_name)
65
+ puts " 🔍 DEBUG: load_user_experience_documents returned #{user_experience.length} documents"
66
+
67
+ puts " 🔍 DEBUG: About to call load_domain_specific_context..."
68
+ domain_specific = load_domain_specific_context(class_name, method_name)
69
+ puts " 🔍 DEBUG: load_domain_specific_context returned: #{domain_specific.inspect}"
70
+
71
+ context = {
72
+ requirements: requirements,
73
+ business_rules: business_rules,
74
+ error_handling: error_handling,
75
+ user_experience: user_experience,
76
+ domain_specific: domain_specific
77
+ }
78
+
79
+ puts " 🔍 DEBUG: Final context keys: #{context.keys}"
80
+ puts " 🔍 DEBUG: Total sources: #{context.values.flatten.length}"
81
+ puts " 📚 Loaded business context from #{context.values.flatten.length} sources"
82
+ context
83
+ end
84
+
85
+ def load_requirements_documents(file_path, class_name = nil, method_name = nil)
86
+ documents = []
87
+ puts " 🔍 DEBUG: load_requirements_documents called with file_path: #{file_path.inspect}, class_name: #{class_name.inspect}, method_name: #{method_name.inspect}"
88
+
89
+ # Look for requirements documents in various locations
90
+ search_paths = [
91
+ File.dirname(file_path),
92
+ Rails.root.join('business_requirements'),
93
+ Rails.root.join('docs'),
94
+ Rails.root.join('requirements'),
95
+ Rails.root.join('PRD'),
96
+ Rails.root.join('specs')
97
+ ]
98
+
99
+ search_paths.each do |search_path|
100
+ next unless Dir.exist?(search_path)
101
+
102
+ Dir.glob(File.join(search_path, '**/*.{md,txt,yml,yaml}')).each do |doc_path|
103
+ next unless File.readable?(doc_path)
104
+
105
+ content = File.read(doc_path)
106
+ if content.match?(/requirement|must|should|shall/i)
107
+ relevance = class_name && method_name ? calculate_relevance(content, class_name, method_name) : 0.5
108
+ documents << {
109
+ path: doc_path,
110
+ type: 'requirement',
111
+ content: content,
112
+ relevance: relevance
113
+ }
114
+ end
115
+ end
116
+ end
117
+
118
+ documents.sort_by { |doc| -doc[:relevance] }
119
+ end
120
+
121
+ def load_business_rules_documents(file_path, class_name = nil, method_name = nil)
122
+ documents = []
123
+ puts " 🔍 DEBUG: load_business_rules_documents called with file_path: #{file_path.inspect}, class_name: #{class_name.inspect}, method_name: #{method_name.inspect}"
124
+
125
+ # Look for business rules documents
126
+ search_paths = [
127
+ File.dirname(file_path),
128
+ Rails.root.join('business_requirements'),
129
+ Rails.root.join('business_rules'),
130
+ Rails.root.join('rules'),
131
+ Rails.root.join('policies')
132
+ ]
133
+
134
+ puts " 🔍 DEBUG: Search paths: #{search_paths.map(&:to_s)}"
135
+
136
+ search_paths.each do |search_path|
137
+ puts " 🔍 DEBUG: Checking search path: #{search_path}"
138
+ puts " 🔍 DEBUG: Directory exists? #{Dir.exist?(search_path)}"
139
+
140
+ next unless Dir.exist?(search_path)
141
+
142
+ puts " 🔍 DEBUG: Searching for documents in: #{search_path}"
143
+ found_files = Dir.glob(File.join(search_path, '**/*.{md,txt,yml,yaml}'))
144
+ puts " 🔍 DEBUG: Found #{found_files.length} files: #{found_files.map { |f| File.basename(f) }}"
145
+
146
+ found_files.each do |doc_path|
147
+ puts " 🔍 DEBUG: Checking file: #{doc_path}"
148
+ puts " 🔍 DEBUG: File readable? #{File.readable?(doc_path)}"
149
+
150
+ next unless File.readable?(doc_path)
151
+
152
+ content = File.read(doc_path)
153
+ puts " 🔍 DEBUG: File content preview: #{content[0..100]}..."
154
+
155
+ if content.match?(/business rule|rule|policy/i)
156
+ puts " 🔍 DEBUG: File matches business rule pattern!"
157
+ relevance = class_name && method_name ? calculate_relevance(content, class_name, method_name) : 0.5
158
+ documents << {
159
+ path: doc_path,
160
+ type: 'business_rule',
161
+ content: content,
162
+ relevance: relevance
163
+ }
164
+ else
165
+ puts " 🔍 DEBUG: File does NOT match business rule pattern"
166
+ end
167
+ end
168
+ end
169
+
170
+ puts " 🔍 DEBUG: Total business rule documents found: #{documents.length}"
171
+ documents.sort_by { |doc| -doc[:relevance] }
172
+ end
173
+
174
+ def load_error_handling_documents(file_path, class_name = nil, method_name = nil)
175
+ documents = []
176
+
177
+ # Look for error handling documentation
178
+ search_paths = [
179
+ File.dirname(file_path),
180
+ Rails.root.join('docs'),
181
+ Rails.root.join('error_handling'),
182
+ Rails.root.join('troubleshooting')
183
+ ]
184
+
185
+ search_paths.each do |search_path|
186
+ next unless Dir.exist?(search_path)
187
+
188
+ Dir.glob(File.join(search_path, '**/*.{md,txt,yml,yaml}')).each do |doc_path|
189
+ next unless File.readable?(doc_path)
190
+
191
+ content = File.read(doc_path)
192
+ if content.match?(/error|exception|failure|nil|null/i)
193
+ relevance = class_name && method_name ? calculate_relevance(content, class_name, method_name) : 0.5
194
+ documents << {
195
+ path: doc_path,
196
+ type: 'error_handling',
197
+ content: content,
198
+ relevance: relevance
199
+ }
200
+ end
201
+ end
202
+ end
203
+
204
+ documents.sort_by { |doc| -doc[:relevance] }
205
+ end
206
+
207
+ def load_user_experience_documents(file_path, class_name = nil, method_name = nil)
208
+ documents = []
209
+
210
+ # Look for UX documentation
211
+ search_paths = [
212
+ File.dirname(file_path),
213
+ Rails.root.join('docs'),
214
+ Rails.root.join('ux'),
215
+ Rails.root.join('user_experience')
216
+ ]
217
+
218
+ search_paths.each do |search_path|
219
+ next unless Dir.exist?(search_path)
220
+
221
+ Dir.glob(File.join(search_path, '**/*.{md,txt,yml,yaml}')).each do |doc_path|
222
+ next unless File.readable?(doc_path)
223
+
224
+ content = File.read(doc_path)
225
+ if content.match?(/user experience|ux|user interface|ui/i)
226
+ relevance = class_name && method_name ? calculate_relevance(content, class_name, method_name) : 0.5
227
+ documents << {
228
+ path: doc_path,
229
+ type: 'user_experience',
230
+ content: content,
231
+ relevance: relevance
232
+ }
233
+ end
234
+ end
235
+ end
236
+
237
+ documents.sort_by { |doc| -doc[:relevance] }
238
+ end
239
+
240
+ def load_domain_specific_context(class_name, method_name)
241
+ # Load domain-specific business context
242
+ domain = determine_domain(class_name)
243
+
244
+ case domain
245
+ when 'order_management'
246
+ load_order_management_context(class_name, method_name)
247
+ when 'user_management'
248
+ load_user_management_context(class_name, method_name)
249
+ when 'payment_processing'
250
+ load_payment_processing_context(class_name, method_name)
251
+ when 'calculator_operations'
252
+ load_calculator_context(class_name, method_name)
253
+ else
254
+ load_general_context(class_name, method_name)
255
+ end
256
+ end
257
+
258
+ def load_order_management_context(class_name, method_name)
259
+ context = {}
260
+
261
+ if method_name.to_s.include?('validate')
262
+ context[:validation_rules] = [
263
+ 'All order items must have valid price and quantity',
264
+ 'Validation errors should provide clear user feedback',
265
+ 'System should not crash due to invalid data'
266
+ ]
267
+ end
268
+
269
+ context
270
+ end
271
+
272
+ def load_calculator_context(class_name, method_name)
273
+ context = {}
274
+
275
+ if method_name.to_s.include?('divide')
276
+ context[:division_rules] = [
277
+ 'Division by zero should be handled gracefully',
278
+ 'Return appropriate fallback values',
279
+ 'Log division errors for audit purposes'
280
+ ]
281
+ end
282
+
283
+ context
284
+ end
285
+
286
+ def load_general_context(class_name, method_name)
287
+ {
288
+ general_rules: [
289
+ 'Errors should not crash the system',
290
+ 'Provide meaningful error messages',
291
+ 'Maintain system stability'
292
+ ]
293
+ }
294
+ end
295
+
296
+ def calculate_relevance(content, class_name, method_name)
297
+ relevance = 0.0
298
+
299
+ # Check for class name mentions
300
+ if content.downcase.include?(class_name.downcase)
301
+ relevance += 0.4
302
+ end
303
+
304
+ # Check for method name mentions
305
+ if content.downcase.include?(method_name.to_s.downcase)
306
+ relevance += 0.3
307
+ end
308
+
309
+ # Check for related terms
310
+ related_terms = ['error', 'exception', 'nil', 'validation', 'calculation']
311
+ related_terms.each do |term|
312
+ if content.downcase.include?(term)
313
+ relevance += 0.1
314
+ end
315
+ end
316
+
317
+ relevance
318
+ end
319
+
320
+ def determine_domain(class_name)
321
+ case class_name.to_s.downcase
322
+ when /order|payment|invoice/
323
+ 'order_management'
324
+ when /user|auth|session/
325
+ 'user_management'
326
+ when /payment|transaction|gateway/
327
+ 'payment_processing'
328
+ when /calculator|math|compute/
329
+ 'calculator_operations'
330
+ else
331
+ 'general'
332
+ end
333
+ end
334
+
335
+ def analyze_error_against_business_rules(error, business_context, class_name, method_name)
336
+ analysis = {
337
+ error_type: error.class.name,
338
+ error_message: error.message,
339
+ business_impact: 'unknown',
340
+ user_experience_impact: 'unknown',
341
+ compliance_issues: [],
342
+ recommended_actions: []
343
+ }
344
+
345
+ # Analyze business impact
346
+ analysis[:business_impact] = assess_business_impact(error, business_context, class_name, method_name)
347
+
348
+ # Analyze user experience impact
349
+ analysis[:user_experience_impact] = assess_user_experience_impact(error, business_context, class_name, method_name)
350
+
351
+ # Check compliance with business rules
352
+ analysis[:compliance_issues] = check_compliance(error, business_context, class_name, method_name)
353
+
354
+ # Generate recommended actions
355
+ analysis[:recommended_actions] = generate_recommended_actions(error, business_context, class_name, method_name)
356
+
357
+ analysis
358
+ end
359
+
360
+ def assess_business_impact(error, business_context, class_name, method_name)
361
+ error_text = error.message.downcase
362
+
363
+ if error_text.include?('nil') || error_text.include?('null')
364
+ # Check if this is a critical business operation
365
+ if method_name.to_s.include?('calculate') || method_name.to_s.include?('total')
366
+ return 'high' # Critical business operation
367
+ else
368
+ return 'medium' # Standard operation
369
+ end
370
+ elsif error_text.include?('division') || error_text.include?('zero')
371
+ return 'medium' # Mathematical operation error
372
+ else
373
+ return 'low' # General error
374
+ end
375
+ end
376
+
377
+ def assess_user_experience_impact(error, business_context, class_name, method_name)
378
+ error_text = error.message.downcase
379
+
380
+ if error_text.include?('nil') || error_text.include?('null')
381
+ return 'high' # User will see broken functionality
382
+ elsif error_text.include?('division') || error_text.include?('zero')
383
+ return 'medium' # Mathematical error, may be confusing
384
+ else
385
+ return 'low' # General error
386
+ end
387
+ end
388
+
389
+ def check_compliance(error, business_context, class_name, method_name)
390
+ compliance_issues = []
391
+
392
+ # Check against business rules
393
+ business_context[:business_rules].each do |rule|
394
+ if rule[:content].downcase.include?('must') || rule[:content].downcase.include?('shall')
395
+ if !rule[:content].downcase.include?('error') && !rule[:content].downcase.include?('exception')
396
+ compliance_issues << "Business rule violation: #{rule[:content][0..100]}..."
397
+ end
398
+ end
399
+ end
400
+
401
+ compliance_issues
402
+ end
403
+
404
+ def generate_recommended_actions(error, business_context, class_name, method_name)
405
+ actions = []
406
+
407
+ # Analyze error type and suggest actions
408
+ if error.message.downcase.include?('nil') || error.message.downcase.include?('null')
409
+ actions << 'Implement nil value validation'
410
+ actions << 'Add default value handling'
411
+ actions << 'Provide user-friendly error messages'
412
+ end
413
+
414
+ if error.message.downcase.include?('division') || error.message.downcase.include?('zero')
415
+ actions << 'Add division by zero protection'
416
+ actions << 'Implement mathematical error handling'
417
+ actions << 'Return appropriate fallback values'
418
+ end
419
+
420
+ # Add business rule specific actions
421
+ business_context[:business_rules].each do |rule|
422
+ if rule[:content].downcase.include?('return') && rule[:content].downcase.include?('nil')
423
+ actions << "Apply business rule: #{rule[:content][0..100]}..."
424
+ end
425
+ end
426
+
427
+ actions.uniq
428
+ end
429
+
430
+ def determine_evolution_strategy(analysis_result, error, class_name, method_name)
431
+ strategy = {
432
+ strategy: 'standard_error_handling',
433
+ business_impact: analysis_result[:business_impact],
434
+ user_experience_impact: analysis_result[:user_experience_impact],
435
+ priority: 'normal',
436
+ approach: 'defensive_programming'
437
+ }
438
+
439
+ # Determine strategy based on business impact
440
+ case analysis_result[:business_impact]
441
+ when 'high'
442
+ strategy[:strategy] = 'business_critical_fix'
443
+ strategy[:priority] = 'high'
444
+ strategy[:approach] = 'robust_error_handling'
445
+ when 'medium'
446
+ strategy[:strategy] = 'enhanced_error_handling'
447
+ strategy[:priority] = 'medium'
448
+ strategy[:approach] = 'graceful_degradation'
449
+ when 'low'
450
+ strategy[:strategy] = 'standard_error_handling'
451
+ strategy[:priority] = 'low'
452
+ strategy[:approach] = 'basic_error_handling'
453
+ end
454
+
455
+ # Adjust based on user experience impact
456
+ if analysis_result[:user_experience_impact] == 'high'
457
+ strategy[:approach] = 'user_experience_focused'
458
+ end
459
+
460
+ strategy
461
+ end
462
+ end
463
+ end
464
+ end