Class: OllamaAgent::Runtime::RollbackSignals

Inherits:
Object
  • Object
show all
Defined in:
lib/ollama_agent/runtime/rollback_signals.rb

Overview

In-memory rolling-window counters for operator rollback heuristics (no persistence).

Constant Summary collapse

DEFAULT_THRESHOLDS =
{
  replay_determinism_violations_per_min: 1,
  recovery_duplicates_per_min: 1,
  mutation_failure_rate: 0.1,
  validator_integrity_mismatches_per_min: 1
}.freeze
WINDOW_TICKS =
60
VALID_EVENTS =
%i[
  replay_determinism_violation
  recovery_duplicate
  mutation_failure
  mutation_success
  validator_integrity_mismatch
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(thresholds: {}) ⇒ RollbackSignals

Returns a new instance of RollbackSignals.

Parameters:

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

    see DEFAULT_THRESHOLDS keys (Float or Integer)



25
26
27
28
29
30
# File 'lib/ollama_agent/runtime/rollback_signals.rb', line 25

def initialize(thresholds: {})
  @thresholds = DEFAULT_THRESHOLDS.merge(thresholds.transform_keys(&:to_sym))
  @current_epoch = 0
  @rows = []
  @mutex = Mutex.new
end

Instance Method Details

#record(event:, payload: {}) ⇒ Object

Parameters:

  • event (Symbol)

    see VALID_EVENTS

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

    optional :epoch / “epoch” logical epoch for this sample

Raises:

  • (ArgumentError)


34
35
36
37
38
39
40
41
42
43
# File 'lib/ollama_agent/runtime/rollback_signals.rb', line 34

def record(event:, payload: {})
  sym = event.to_sym
  raise ArgumentError, "unknown rollback signal #{sym.inspect}" unless VALID_EVENTS.include?(sym)

  @mutex.synchronize do
    epoch = (payload[:epoch] || payload["epoch"] || @current_epoch).to_i
    @rows << { epoch: epoch, event: sym, ts_wall: Time.now.to_f }
    prune_unlocked!
  end
end

#should_rollback?Hash

rubocop:disable Naming/PredicateMethod, Metrics/MethodLength, Metrics/AbcSize – operator-facing query name + explicit thresholds

Returns:

  • (Hash)

    :trigger (Boolean), :reasons (Array<String>)



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/ollama_agent/runtime/rollback_signals.rb', line 55

def should_rollback?
  snap = @mutex.synchronize { @rows.dup }
  reasons = []
  t = @thresholds

  reasons << "replay_determinism_violation threshold breached" if count_event(snap, :replay_determinism_violation) >= t[:replay_determinism_violations_per_min]

  reasons << "recovery_duplicate threshold breached" if count_event(snap, :recovery_duplicate) >= t[:recovery_duplicates_per_min]

  reasons << "validator_integrity_mismatch threshold breached" if count_event(snap, :validator_integrity_mismatch) >= t[:validator_integrity_mismatches_per_min]

  mf = count_event(snap, :mutation_failure)
  ms = count_event(snap, :mutation_success)
  total = mf + ms
  reasons << "mutation_failure_rate threshold breached" if total.positive? && (mf.to_f / total) >= t[:mutation_failure_rate].to_f

  { trigger: reasons.any?, reasons: reasons }
end

#tick(epoch:) ⇒ Object

Advance logical epoch and evict samples older than the 60-tick window.



46
47
48
49
50
51
# File 'lib/ollama_agent/runtime/rollback_signals.rb', line 46

def tick(epoch:)
  @mutex.synchronize do
    @current_epoch = epoch.to_i
    prune_unlocked!
  end
end