Module: RubynCode::Learning::InstinctMethods

Defined in:
lib/rubyn_code/learning/instinct.rb

Overview

rubocop:disable Metrics/ModuleLength – instinct CRUD + decay logic with DB operations

Constant Summary collapse

MIN_CONFIDENCE =

The minimum confidence threshold below which instincts are considered stale.

0.05
CONFIDENCE_LABELS =

Confidence label thresholds, checked in descending order.

[
  [0.9, 'near-certain'],
  [0.7, 'confident'],
  [0.5, 'moderate'],
  [0.3, 'tentative']
].freeze

Class Method Summary collapse

Class Method Details

.apply_decay(instinct, current_time) ⇒ Instinct

Applies time-based decay to an instinct’s confidence score. Confidence decays based on how long it has been since the instinct was last used (updated_at).

Parameters:

  • instinct (Instinct)

    the instinct to decay

  • current_time (Time)

    the reference time for decay calculation

Returns:

  • (Instinct)

    a new instinct with decayed confidence



61
62
63
64
65
66
67
68
69
# File 'lib/rubyn_code/learning/instinct.rb', line 61

def apply_decay(instinct, current_time)
  elapsed_days = (current_time - instinct.updated_at).to_f / 86_400
  return instinct if elapsed_days <= 0

  decay_factor = Math.exp(-instinct.decay_rate * elapsed_days)
  new_confidence = (instinct.confidence * decay_factor).clamp(MIN_CONFIDENCE, 1.0)

  instinct.with(confidence: new_confidence)
end

.apply_decay_to_db(db, instinct_id, new_confidence) ⇒ Object



195
196
197
198
199
200
201
# File 'lib/rubyn_code/learning/instinct.rb', line 195

def apply_decay_to_db(db, instinct_id, new_confidence)
  if new_confidence <= MIN_CONFIDENCE
    db.execute('DELETE FROM instincts WHERE id = ?', [instinct_id])
  else
    db.execute('UPDATE instincts SET confidence = ? WHERE id = ?', [new_confidence, instinct_id])
  end
end

.compute_decayed_confidence(row, elapsed_days) ⇒ Object



190
191
192
193
# File 'lib/rubyn_code/learning/instinct.rb', line 190

def compute_decayed_confidence(row, elapsed_days)
  decay_factor = Math.exp(-row['decay_rate'].to_f * elapsed_days)
  (row['confidence'].to_f * decay_factor).clamp(MIN_CONFIDENCE, 1.0)
end

.compute_elapsed_days(row, now) ⇒ Object



183
184
185
186
187
188
# File 'lib/rubyn_code/learning/instinct.rb', line 183

def compute_elapsed_days(row, now)
  updated_at = Time.parse(row['updated_at'].to_s)
  (now - updated_at).to_f / 86_400
rescue StandardError
  0
end

.compute_reinforcement(instinct, helpful) ⇒ Object



88
89
90
91
92
93
94
95
96
# File 'lib/rubyn_code/learning/instinct.rb', line 88

def compute_reinforcement(instinct, helpful)
  if helpful
    boost = 0.1 * (1.0 - instinct.confidence)
    [(instinct.confidence + boost).clamp(0.0, 1.0), instinct.times_helpful + 1]
  else
    penalty = 0.15 * instinct.confidence
    [(instinct.confidence - penalty).clamp(MIN_CONFIDENCE, 1.0), instinct.times_helpful]
  end
end

.confidence_label(score) ⇒ String

Returns a human-readable label for a confidence score.

Parameters:

  • score (Float)

    the confidence score (0.0 to 1.0)

Returns:

  • (String)

    one of “near-certain”, “confident”, “moderate”, “tentative”, or “unreliable”



103
104
105
106
107
108
109
# File 'lib/rubyn_code/learning/instinct.rb', line 103

def confidence_label(score)
  CONFIDENCE_LABELS.each do |(threshold, label)|
    return label if score >= threshold
  end

  'unreliable'
end

.decay_all(db, project_path:) ⇒ void

This method returns an undefined value.

Applies time-based decay to all instincts in the database for a given project, removing any that fall below minimum confidence.

Parameters:

  • db (DB::Connection)

    the database connection

  • project_path (String)

    the project root path



163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rubyn_code/learning/instinct.rb', line 163

def decay_all(db, project_path:)
  rows = db.query(
    'SELECT id, confidence, decay_rate, updated_at FROM instincts WHERE project_path = ?',
    [project_path]
  ).to_a

  now = Time.now
  rows.each { |row| decay_single_row(db, row, now) }
rescue StandardError => e
  warn "[Learning::InstinctMethods] Failed to decay instincts: #{e.message}"
end

.decay_single_row(db, row, now) ⇒ Object



175
176
177
178
179
180
181
# File 'lib/rubyn_code/learning/instinct.rb', line 175

def decay_single_row(db, row, now)
  elapsed_days = compute_elapsed_days(row, now)
  return if elapsed_days <= 0

  new_confidence = compute_decayed_confidence(row, elapsed_days)
  apply_decay_to_db(db, row['id'], new_confidence)
end

.reinforce(instinct, helpful: true) ⇒ Instinct

Reinforces an instinct by increasing or decreasing confidence based on whether the application was helpful.

Parameters:

  • instinct (Instinct)

    the instinct to reinforce

  • helpful (Boolean) (defaults to: true)

    whether the instinct was helpful this time

Returns:

  • (Instinct)

    a new instinct with updated confidence and counters



77
78
79
80
81
82
83
84
85
86
# File 'lib/rubyn_code/learning/instinct.rb', line 77

def reinforce(instinct, helpful: true)
  new_confidence, new_helpful = compute_reinforcement(instinct, helpful)

  instinct.with(
    confidence: new_confidence,
    times_applied: instinct.times_applied + 1,
    times_helpful: new_helpful,
    updated_at: Time.now
  )
end

.reinforce_in_db(instinct_id, db, helpful: true) ⇒ void

This method returns an undefined value.

Reinforces an instinct in the database by updating confidence and counters based on whether the application was helpful.

Parameters:

  • instinct_id (String)

    the instinct ID in the database

  • db (DB::Connection)

    the database connection

  • helpful (Boolean) (defaults to: true)

    whether the instinct was helpful



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rubyn_code/learning/instinct.rb', line 118

def reinforce_in_db(instinct_id, db, helpful: true)
  now = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')

  if helpful
    reinforce_positive(db, instinct_id, now)
  else
    reinforce_negative(db, instinct_id, now)
  end
rescue StandardError => e
  warn "[Learning::InstinctMethods] Failed to reinforce instinct #{instinct_id}: #{e.message}"
end

.reinforce_negative(db, instinct_id, now) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/rubyn_code/learning/instinct.rb', line 144

def reinforce_negative(db, instinct_id, now)
  db.execute(
    <<~SQL.tr("\n", ' ').strip,
      UPDATE instincts
      SET confidence = MAX(#{MIN_CONFIDENCE}, confidence - 0.15 * confidence),
          times_applied = times_applied + 1,
          updated_at = ?
      WHERE id = ?
    SQL
    [now, instinct_id]
  )
end

.reinforce_positive(db, instinct_id, now) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rubyn_code/learning/instinct.rb', line 130

def reinforce_positive(db, instinct_id, now)
  db.execute(
    <<~SQL.tr("\n", ' ').strip,
      UPDATE instincts
      SET confidence = MIN(1.0, confidence + 0.1 * (1.0 - confidence)),
          times_applied = times_applied + 1,
          times_helpful = times_helpful + 1,
          updated_at = ?
      WHERE id = ?
    SQL
    [now, instinct_id]
  )
end