Class: Ralph::Storage::History

Inherits:
Object
  • Object
show all
Includes:
Helpers
Defined in:
lib/ralph/storage/history.rb

Overview

Manages iteration history and performance tracking.

Stores everything as plain hashes. No structs, no ceremony. Each iteration is a hash appended to an array, persisted as JSON.

Constant Summary collapse

EMPTY_HISTORY =
{
  "iterations" => [],
  "total_duration_ms" => 0,
  "struggle_indicators" => {
    "repeated_errors" => {},
    "no_progress_iterations" => 0,
    "short_iterations" => 0
  }
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers

#check_completion, #escape_regex, #format_duration, #format_duration_long, #format_tool_summary, #now_ms, #strip_ansi, #which

Constructor Details

#initializeHistory

Returns a new instance of History.



27
28
29
30
# File 'lib/ralph/storage/history.rb', line 27

def initialize
  @history = self.class.empty_history
  self.class.save_history(@history)
end

Instance Attribute Details

#historyObject (readonly)

Returns the value of attribute history.



25
26
27
# File 'lib/ralph/storage/history.rb', line 25

def history
  @history
end

Class Method Details

.clear_historyObject



100
101
102
103
104
# File 'lib/ralph/storage/history.rb', line 100

def clear_history
  File.delete(history_path) if File.exist?(history_path)
rescue StandardError
  # ignore
end

.empty_historyObject



83
84
85
# File 'lib/ralph/storage/history.rb', line 83

def empty_history
  JSON.parse(JSON.generate(EMPTY_HISTORY))
end

.history_pathObject



79
80
81
# File 'lib/ralph/storage/history.rb', line 79

def history_path
  File.join(state_dir, "ralph-history.json")
end

.load_historyObject



92
93
94
95
96
97
98
# File 'lib/ralph/storage/history.rb', line 92

def load_history
  return empty_history unless File.exist?(history_path)

  JSON.parse(File.read(history_path))
rescue StandardError
  empty_history
end

.save_history(history) ⇒ Object



87
88
89
90
# File 'lib/ralph/storage/history.rb', line 87

def save_history(history)
  FileUtils.mkdir_p(state_dir)
  File.write(history_path, JSON.pretty_generate(history))
end

.state_dirObject



75
76
77
# File 'lib/ralph/storage/history.rb', line 75

def state_dir
  File.join(Dir.pwd, ".ralph")
end

Instance Method Details

#record(state_iteration:, iteration_start:, result:, struggle_indicators:) ⇒ Object

Record a completed iteration.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ralph/storage/history.rb', line 33

def record(state_iteration:, iteration_start:, result:, struggle_indicators:)
  entry = {
    "iteration" => state_iteration,
    "started_at" => Time.at(iteration_start / 1000.0).utc.iso8601,
    "ended_at" => Time.now.utc.iso8601,
    "duration_ms" => result.duration_ms,
    "tools_used" => result.tool_counts,
    "files_modified" => result.files_modified,
    "exit_code" => result.exit_code,
    "completion_detected" => result.completion_detected,
    "errors" => result.errors
  }

  append(entry, result.duration_ms, struggle_indicators)
end

#record_error(state_iteration:, iteration_start:, error:) ⇒ Object

Record an iteration that raised an exception before producing a result.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/ralph/storage/history.rb', line 50

def record_error(state_iteration:, iteration_start:, error:)
  iteration_duration = now_ms - iteration_start

  entry = {
    "iteration" => state_iteration,
    "started_at" => Time.at(iteration_start / 1000.0).utc.iso8601,
    "ended_at" => Time.now.utc.iso8601,
    "duration_ms" => iteration_duration,
    "tools_used" => {},
    "files_modified" => [],
    "exit_code" => -1,
    "completion_detected" => false,
    "errors" => [error.to_s[0, 200]]
  }

  append(entry, iteration_duration, nil)
end

#total_duration_msObject



68
69
70
# File 'lib/ralph/storage/history.rb', line 68

def total_duration_ms
  @history["total_duration_ms"]
end