Class: Aidp::Harness::RSpecCommandOptimizer

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/harness/rspec_command_optimizer.rb

Overview

Optimizes RSpec command execution by using --only-failures on subsequent runs. This dramatically reduces both execution time and output volume when fixing failing tests during work loops.

Requirements:

  • RSpec must be configured with example_status_persistence_file_path in spec_helper.rb
  • A .rspec_status file (or configured path) must exist from a previous run

Examples:

optimizer = RSpecCommandOptimizer.new("/path/to/project")
result = optimizer.optimize_command("bundle exec rspec", iteration: 2, had_failures: true)
# => "bundle exec rspec --only-failures"

Constant Summary collapse

DEFAULT_STATUS_PATHS =

Default paths where RSpec stores example status

[
  ".rspec_status",
  "tmp/.rspec_status",
  "spec/.rspec_status"
].freeze
SPEC_HELPER_PATHS =

Common spec_helper paths to check for persistence configuration

[
  "spec/spec_helper.rb",
  "spec/rails_helper.rb"
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_dir) ⇒ RSpecCommandOptimizer

Returns a new instance of RSpecCommandOptimizer.



34
35
36
37
38
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 34

def initialize(project_dir)
  @project_dir = project_dir
  @status_file_cache = nil
  @persistence_configured_cache = nil
end

Instance Attribute Details

#project_dirObject (readonly)

Returns the value of attribute project_dir.



32
33
34
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 32

def project_dir
  @project_dir
end

Instance Method Details

#check_persistence_configurationHash

Check if RSpec persistence is properly configured in this project

Returns:

  • (Hash)

    { configured: Boolean, file_path: String, message: String }



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 80

def check_persistence_configuration
  return @persistence_configured_cache if @persistence_configured_cache

  @persistence_configured_cache = begin
    # Check if any spec_helper configures persistence
    configured_in_spec_helper = SPEC_HELPER_PATHS.any? do |path|
      full_path = File.join(@project_dir, path)
      next false unless File.exist?(full_path)

      content = File.read(full_path, encoding: "UTF-8")
      content.include?("example_status_persistence_file_path")
    end

    if configured_in_spec_helper
      status_file = find_status_file
      {
        configured: true,
        file_path: status_file,
        message: "RSpec persistence configured" + (status_file ? " (#{status_file} exists)" : " (waiting for first run)")
      }
    else
      {
        configured: false,
        file_path: nil,
        message: "RSpec persistence not configured. Add to spec_helper.rb:\n" \
                 "  config.example_status_persistence_file_path = '.rspec_status'"
      }
    end
  end
end

#find_status_fileString?

Find the RSpec status file if it exists

Returns:

  • (String, nil)

    Path to status file or nil if not found



114
115
116
117
118
119
120
121
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 114

def find_status_file
  return @status_file_cache if @status_file_cache

  @status_file_cache = DEFAULT_STATUS_PATHS.find do |path|
    full_path = File.join(@project_dir, path)
    File.exist?(full_path)
  end
end

#optimize_command(command, iteration:, had_failures:) ⇒ Hash

Optimize an RSpec command based on iteration context

Parameters:

  • command (String)

    The original RSpec command

  • iteration (Integer)

    Current iteration number (1-indexed)

  • had_failures (Boolean)

    Whether the previous iteration had test failures

Returns:

  • (Hash)

    { command: String, optimized: Boolean, reason: String }



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 46

def optimize_command(command, iteration:, had_failures:)
  return skip_optimization(command, "not an RSpec command") unless rspec_command?(command)
  return skip_optimization(command, "first iteration") if iteration <= 1
  return skip_optimization(command, "no previous failures") unless had_failures
  return skip_optimization(command, "already has --only-failures") if command.include?("--only-failures")

  status_file = find_status_file
  unless status_file
    Aidp.log_debug("rspec_optimizer", "no_status_file",
      project_dir: @project_dir,
      checked_paths: DEFAULT_STATUS_PATHS)

    return skip_optimization(command, "no .rspec_status file found - see setup instructions")
  end

  optimized_command = add_only_failures_flag(command)

  Aidp.log_info("rspec_optimizer", "command_optimized",
    original: command,
    optimized: optimized_command,
    iteration: iteration,
    status_file: status_file)

  {
    command: optimized_command,
    optimized: true,
    reason: "using --only-failures (iteration #{iteration})",
    status_file: status_file
  }
end

#reset_caches!Object

Reset caches (useful after test runs that may create status file)



133
134
135
136
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 133

def reset_caches!
  @status_file_cache = nil
  @persistence_configured_cache = nil
end

#rspec_command?(command) ⇒ Boolean

Check if command is an RSpec command

Parameters:

  • command (String)

    Command to check

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/aidp/harness/rspec_command_optimizer.rb', line 127

def rspec_command?(command)
  return false unless command.is_a?(String)
  command.downcase.include?("rspec")
end