Class: Ace::Review::Molecules::TaskReportSaver

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/review/molecules/task_report_saver.rb

Overview

Save review reports to task directories with compact ID filenames

Class Method Summary collapse

Class Method Details

.archive_feedback(task_path, feedback_file) ⇒ Hash

Archive a feedback file by moving it to the task’s feedback/_archived/ directory

Parameters:

  • task_path (String)

    Path to the task directory

  • feedback_file (String)

    Path to the feedback file to archive

Returns:

  • (Hash)

    Result with :success, :path, or :error



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/ace/review/molecules/task_report_saver.rb', line 134

def self.archive_feedback(task_path, feedback_file)
  # Validate inputs
  return {success: false, error: "Task directory not found: #{task_path}"} unless Dir.exist?(task_path)
  return {success: false, error: "Feedback file not found: #{feedback_file}"} unless File.exist?(feedback_file)

  # Create feedback/_archived/ subdirectory if it doesn't exist
  archive_dir = feedback_archive_path(task_path)
  begin
    FileUtils.mkdir_p(archive_dir)
  rescue SystemCallError, IOError => e
    return {success: false, error: "Cannot create archive directory: #{e.message}"}
  end

  # Move feedback file to archive
  filename = File.basename(feedback_file)
  archive_path = File.join(archive_dir, filename)

  begin
    FileUtils.mv(feedback_file, archive_path)
    {success: true, path: archive_path}
  rescue SystemCallError, IOError => e
    {success: false, error: "Failed to archive feedback: #{e.message}"}
  end
end

.extract_provider(model) ⇒ String

Extract provider name from model string

Parameters:

  • model (String)

    Model identifier (e.g., “google:gemini-2.5-flash”, “gpt-4”)

Returns:

  • (String)

    Provider name or sanitized model name



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ace/review/molecules/task_report_saver.rb', line 64

def self.extract_provider(model)
  # Check for provider prefix (e.g., "google:", "openai:")
  if model.include?(":")
    provider = model.split(":").first
    provider.gsub(/[^a-zA-Z0-9\-_]/, "-").downcase
  else
    # Use first part of model name (e.g., "gpt-4" -> "gpt", "claude-3" -> "claude")
    parts = model.split("-")
    if parts.length > 1 && parts.first =~ /^[a-z]+$/i
      parts.first.downcase
    else
      # Fallback: sanitize entire model name
      model.gsub(/[^a-zA-Z0-9\-_]/, "-").downcase.split("-").first
    end
  end
end

.feedback_archive_path(task_path) ⇒ String

Get the feedback archive directory path for a task

Parameters:

  • task_path (String)

    Path to the task directory

Returns:

  • (String)

    The feedback archive directory path



95
96
97
# File 'lib/ace/review/molecules/task_report_saver.rb', line 95

def self.feedback_archive_path(task_path)
  File.join(task_path, "feedback", "_archived")
end

.feedback_path(task_path) ⇒ String

Get the feedback directory path for a task

Parameters:

  • task_path (String)

    Path to the task directory

Returns:

  • (String)

    The feedback directory path



88
89
90
# File 'lib/ace/review/molecules/task_report_saver.rb', line 88

def self.feedback_path(task_path)
  File.join(task_path, "feedback")
end

.generate_filename(review_data) ⇒ String

Generate filename with compact ID for review report

Parameters:

  • review_data (Hash)

    Review metadata (preset, model, etc.)

Returns:

  • (String)

    Filename with format: compact_id-model-preset-review.md



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/ace/review/molecules/task_report_saver.rb', line 46

def self.generate_filename(review_data)
  compact_id = Ace::B36ts.encode(Time.now)

  # Use full model slug for uniqueness (e.g., "google:gemini-2.5-flash" -> "google-gemini-2-5-flash")
  model = review_data[:model] || "unknown"
  model_slug = Ace::Review::Atoms::SlugGenerator.generate(model)

  preset = review_data[:preset] || "default"

  # Sanitize preset name for filename
  preset_slug = Ace::Review::Atoms::SlugGenerator.generate(preset)

  "#{compact_id}-#{model_slug}-#{preset_slug}-review.md"
end

.save(task_dir, review_file, review_data) ⇒ Hash

Save a review report to a task’s reviews/ directory

Parameters:

  • task_dir (String)

    Path to the task directory

  • review_file (String)

    Path to the review file to copy

  • review_data (Hash)

    Review metadata (preset, model, etc.)

Returns:

  • (Hash)

    Result with :success, :path, or :error



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ace/review/molecules/task_report_saver.rb', line 17

def self.save(task_dir, review_file, review_data)
  # Validate inputs
  return {success: false, error: "Task directory not found: #{task_dir}"} unless Dir.exist?(task_dir)
  return {success: false, error: "Review file not found: #{review_file}"} unless File.exist?(review_file)

  # Create reviews/ subdirectory if it doesn't exist
  reviews_dir = File.join(task_dir, "reviews")
  begin
    FileUtils.mkdir_p(reviews_dir)
  rescue SystemCallError, IOError => e
    return {success: false, error: "Cannot create reviews directory: #{e.message}"}
  end

  # Generate filename
  filename = generate_filename(review_data)
  output_path = File.join(reviews_dir, filename)

  # Copy review to task directory
  begin
    FileUtils.cp(review_file, output_path)
    {success: true, path: output_path}
  rescue SystemCallError, IOError => e
    {success: false, error: "Failed to save review: #{e.message}"}
  end
end

.save_feedback(task_path, feedback_file, feedback_data = {}) ⇒ Hash

Save a feedback file to a task’s feedback/ directory

Parameters:

  • task_path (String)

    Path to the task directory

  • feedback_file (String)

    Path to the feedback file to copy

  • feedback_data (Hash) (defaults to: {})

    Optional metadata (currently unused, for future extension)

Returns:

  • (Hash)

    Result with :success, :path, or :error



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/ace/review/molecules/task_report_saver.rb', line 104

def self.save_feedback(task_path, feedback_file, feedback_data = {})
  # Validate inputs
  return {success: false, error: "Task directory not found: #{task_path}"} unless Dir.exist?(task_path)
  return {success: false, error: "Feedback file not found: #{feedback_file}"} unless File.exist?(feedback_file)

  # Create feedback/ subdirectory if it doesn't exist
  feedback_dir = feedback_path(task_path)
  begin
    FileUtils.mkdir_p(feedback_dir)
  rescue SystemCallError, IOError => e
    return {success: false, error: "Cannot create feedback directory: #{e.message}"}
  end

  # Use original filename for feedback files (they already have meaningful names)
  filename = File.basename(feedback_file)
  output_path = File.join(feedback_dir, filename)

  # Copy feedback file to task directory
  begin
    FileUtils.cp(feedback_file, output_path)
    {success: true, path: output_path}
  rescue SystemCallError, IOError => e
    {success: false, error: "Failed to save feedback: #{e.message}"}
  end
end