Class: Aidp::Database::Repositories::TemplateVersionRepository
- Inherits:
-
Aidp::Database::Repository
- Object
- Aidp::Database::Repository
- Aidp::Database::Repositories::TemplateVersionRepository
- Defined in:
- lib/aidp/database/repositories/template_version_repository.rb
Overview
Repository for template_versions table Manages versioned prompt templates with feedback-based selection
Per issue #402:
- Store template versions in SQLite
- Track positive/negative votes per version
- Retain last 5 versions, ensuring at least 2 positive-feedback versions
- Select best version based on positive vote count
Constant Summary collapse
- MIN_VERSIONS =
Minimum versions to retain per template
5- MIN_POSITIVE_VERSIONS =
Minimum positive-feedback versions to retain
2
Instance Attribute Summary
Attributes inherited from Aidp::Database::Repository
Instance Method Summary collapse
-
#activate(id:) ⇒ Hash
Activate a specific version.
-
#active_version(template_id:) ⇒ Hash?
Get the active version for a template.
-
#any?(template_id:) ⇒ Boolean
Check if any versions exist for a template.
-
#best_version(template_id:) ⇒ Hash?
Get the best version for a template based on positive votes Prioritizes higher positive vote counts.
-
#count(template_id:) ⇒ Integer
Count versions for a template.
-
#create(template_id:, content:, parent_version_id: nil, metadata: nil) ⇒ Hash
Create a new template version.
-
#find(id:) ⇒ Hash?
Get a specific version by ID.
-
#initialize(project_dir: Dir.pwd) ⇒ TemplateVersionRepository
constructor
A new instance of TemplateVersionRepository.
-
#list(template_id:, limit: 20) ⇒ Array<Hash>
Get all versions for a template.
-
#prune_old_versions(template_id:) ⇒ Hash
Prune old versions, keeping: - At least MIN_VERSIONS (5) versions - At least MIN_POSITIVE_VERSIONS (2) positive-feedback versions.
-
#record_negative_vote(id:) ⇒ Hash
Record a negative vote for a version.
-
#record_positive_vote(id:) ⇒ Hash
Record a positive vote for a version.
-
#template_ids ⇒ Array<String>
Get all unique template IDs with versions.
-
#versions_needing_evolution(template_id: nil) ⇒ Array<Hash>
Get versions needing evolution (have negative votes).
Constructor Details
#initialize(project_dir: Dir.pwd) ⇒ TemplateVersionRepository
Returns a new instance of TemplateVersionRepository.
24 25 26 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 24 def initialize(project_dir: Dir.pwd) super(project_dir: project_dir, table_name: "template_versions") end |
Instance Method Details
#activate(id:) ⇒ Hash
Activate a specific version
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 184 def activate(id:) version = find(id: id) return {success: false, error: "Version not found"} unless version Aidp.log_debug("template_version_repository", "activating_version", id: id, template_id: version[:template_id]) transaction do # Deactivate all versions for this template execute( "UPDATE template_versions SET is_active = 0 WHERE project_dir = ? AND template_id = ?", [project_dir, version[:template_id]] ) # Activate the specified version execute( "UPDATE template_versions SET is_active = 1 WHERE id = ? AND project_dir = ?", [id, project_dir] ) end Aidp.log_info("template_version_repository", "version_activated", id: id, template_id: version[:template_id]) {success: true} rescue => e Aidp.log_error("template_version_repository", "activation_failed", id: id, error: e.) {success: false, error: e.} end |
#active_version(template_id:) ⇒ Hash?
Get the active version for a template
97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 97 def active_version(template_id:) row = query_one( <<~SQL, SELECT * FROM template_versions WHERE project_dir = ? AND template_id = ? AND is_active = 1 LIMIT 1 SQL [project_dir, template_id] ) deserialize_version(row) end |
#any?(template_id:) ⇒ Boolean
Check if any versions exist for a template
322 323 324 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 322 def any?(template_id:) count(template_id: template_id).positive? end |
#best_version(template_id:) ⇒ Hash?
Get the best version for a template based on positive votes Prioritizes higher positive vote counts
222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 222 def best_version(template_id:) row = query_one( <<~SQL, SELECT * FROM template_versions WHERE project_dir = ? AND template_id = ? ORDER BY positive_votes DESC, version_number DESC LIMIT 1 SQL [project_dir, template_id] ) deserialize_version(row) end |
#count(template_id:) ⇒ Integer
Count versions for a template
311 312 313 314 315 316 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 311 def count(template_id:) query_value( "SELECT COUNT(*) FROM template_versions WHERE project_dir = ? AND template_id = ?", [project_dir, template_id] ) || 0 end |
#create(template_id:, content:, parent_version_id: nil, metadata: nil) ⇒ Hash
Create a new template version
35 36 37 38 39 40 41 42 43 44 45 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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 35 def create(template_id:, content:, parent_version_id: nil, metadata: nil) # Validate content is present if content.nil? || content.to_s.strip.empty? Aidp.log_error("template_version_repository", "invalid_content", template_id: template_id, error: "Content cannot be nil or empty") return {success: false, error: "Content cannot be nil or empty"} end Aidp.log_debug("template_version_repository", "creating_version", template_id: template_id, parent_version_id: parent_version_id) transaction do # Get next version number for this template next_version = next_version_number(template_id) # Deactivate all existing versions for this template execute( "UPDATE template_versions SET is_active = 0 WHERE project_dir = ? AND template_id = ?", [project_dir, template_id] ) # Insert new version as active execute( insert_sql([ :project_dir, :template_id, :version_number, :content, :parent_version_id, :is_active, :positive_votes, :negative_votes, :metadata ]), [ project_dir, template_id, next_version, content, parent_version_id, 1, # is_active 0, # positive_votes 0, # negative_votes serialize_json() ] ) id = last_insert_row_id Aidp.log_info("template_version_repository", "version_created", template_id: template_id, version_number: next_version, id: id) {success: true, id: id, version_number: next_version} end rescue => e Aidp.log_error("template_version_repository", "create_failed", template_id: template_id, error: e.) {success: false, error: e.} end |
#find(id:) ⇒ Hash?
Get a specific version by ID
114 115 116 117 118 119 120 121 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 114 def find(id:) row = query_one( "SELECT * FROM template_versions WHERE id = ? AND project_dir = ?", [id, project_dir] ) deserialize_version(row) end |
#list(template_id:, limit: 20) ⇒ Array<Hash>
Get all versions for a template
128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 128 def list(template_id:, limit: 20) rows = query( <<~SQL, SELECT * FROM template_versions WHERE project_dir = ? AND template_id = ? ORDER BY version_number DESC LIMIT ? SQL [project_dir, template_id, limit] ) rows.map { |row| deserialize_version(row) }.compact end |
#prune_old_versions(template_id:) ⇒ Hash
Prune old versions, keeping:
- At least MIN_VERSIONS (5) versions
- At least MIN_POSITIVE_VERSIONS (2) positive-feedback versions
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 270 def prune_old_versions(template_id:) Aidp.log_debug("template_version_repository", "pruning_versions", template_id: template_id) # Capture active version reference before list/delete operations. # This ensures we never prune the currently active version, even if # activation changes during pruning (defensive programming). active = active_version(template_id: template_id) versions = list(template_id: template_id, limit: 100) return {success: true, pruned_count: 0} if versions.size <= MIN_VERSIONS # Identify versions to keep versions_to_keep = identify_versions_to_keep(versions) versions_to_prune = versions.reject { |v| versions_to_keep.include?(v[:id]) } # Never prune the active version versions_to_prune.reject! { |v| v[:id] == active&.dig(:id) } pruned_count = 0 versions_to_prune.each do |version| execute("DELETE FROM template_versions WHERE id = ?", [version[:id]]) pruned_count += 1 end Aidp.log_info("template_version_repository", "versions_pruned", template_id: template_id, pruned_count: pruned_count, remaining_count: versions.size - pruned_count) {success: true, pruned_count: pruned_count} rescue => e Aidp.log_error("template_version_repository", "prune_failed", template_id: template_id, error: e.) {success: false, error: e.} end |
#record_negative_vote(id:) ⇒ Hash
Record a negative vote for a version
165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 165 def record_negative_vote(id:) Aidp.log_debug("template_version_repository", "recording_negative_vote", id: id) execute( "UPDATE template_versions SET negative_votes = negative_votes + 1 WHERE id = ? AND project_dir = ?", [id, project_dir] ) {success: true} rescue => e Aidp.log_error("template_version_repository", "negative_vote_failed", id: id, error: e.) {success: false, error: e.} end |
#record_positive_vote(id:) ⇒ Hash
Record a positive vote for a version
146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 146 def record_positive_vote(id:) Aidp.log_debug("template_version_repository", "recording_positive_vote", id: id) execute( "UPDATE template_versions SET positive_votes = positive_votes + 1 WHERE id = ? AND project_dir = ?", [id, project_dir] ) {success: true} rescue => e Aidp.log_error("template_version_repository", "positive_vote_failed", id: id, error: e.) {success: false, error: e.} end |
#template_ids ⇒ Array<String>
Get all unique template IDs with versions
329 330 331 332 333 334 335 336 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 329 def template_ids rows = query( "SELECT DISTINCT template_id FROM template_versions WHERE project_dir = ? ORDER BY template_id", [project_dir] ) rows.map { |r| r["template_id"] } end |
#versions_needing_evolution(template_id: nil) ⇒ Array<Hash>
Get versions needing evolution (have negative votes)
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/aidp/database/repositories/template_version_repository.rb', line 240 def versions_needing_evolution(template_id: nil) rows = if template_id query( <<~SQL, SELECT * FROM template_versions WHERE project_dir = ? AND template_id = ? AND negative_votes > 0 ORDER BY negative_votes DESC SQL [project_dir, template_id] ) else query( <<~SQL, SELECT * FROM template_versions WHERE project_dir = ? AND negative_votes > 0 ORDER BY negative_votes DESC SQL [project_dir] ) end rows.map { |row| deserialize_version(row) }.compact end |