Class: Insika::ModelVisibleTraceStore

Inherits:
Object
  • Object
show all
Defined in:
lib/insika/model_visible_trace_store.rb

Overview

— the durable half of the conformance claim: what the model received, per (task, turn), captured at the RubyLLM boundary and persisted.

One record per (task, turn, part) under the scope "model_visible_traces", key "model_visible:<task_id>:turn::" — part separates the turn's own ask ("turn") from engine-internal asks that are model-visible too (the WS4 routing classifier, "routing").

A TRACE, best-effort by construction: record rescues everything -> nil (a log must never break a turn — the house rule, tool_trace_store.rb). The record is an UPSERT by (task, turn, part): a resumed turn re-records its ask in place (the ContextTraceStore idiom), never duplicates.

Constant Summary collapse

SCOPE =
"model_visible_traces"

Instance Method Summary collapse

Constructor Details

#initialize(store:) ⇒ ModelVisibleTraceStore

Returns a new instance of ModelVisibleTraceStore.



19
20
21
# File 'lib/insika/model_visible_trace_store.rb', line 19

def initialize(store:)
  @store = store
end

Instance Method Details

#find(task_id, turn:, part: "turn") ⇒ Object

-> ModelVisible | nil.



34
35
36
37
# File 'lib/insika/model_visible_trace_store.rb', line 34

def find(task_id, turn:, part: "turn")
  raw = @store.get(SCOPE, key(task_id, turn, part))
  raw && ModelVisible.from_h(raw)
end

#for_task(task_id, part: "turn") ⇒ Object

-> [ModelVisible] the task's records for part, ordered by turn.



40
41
42
43
44
45
46
47
# File 'lib/insika/model_visible_trace_store.rb', line 40

def for_task(task_id, part: "turn")
  @store.list(SCOPE, key_prefix(task_id)).filter_map do |k|
    next unless k.end_with?(":#{part}")

    n = k[/:turn:(\d+):/, 1]
    n && [Integer(n), ModelVisible.from_h(@store.get(SCOPE, k))]
  end.sort_by(&:first).map(&:last)
end

#purge(task_id) ⇒ Object

Removes every record for a task (retention/LGPD). -> Integer (removed).



50
51
52
53
54
# File 'lib/insika/model_visible_trace_store.rb', line 50

def purge(task_id)
  keys = @store.list(SCOPE, key_prefix(task_id))
  keys.each { |k| @store.delete(SCOPE, k) }
  keys.size
end

#record(task_id:, turn:, part: "turn", payload:) ⇒ Object

-> ModelVisible | nil (nil = the record failed — the turn proceeds).



24
25
26
27
28
29
30
31
# File 'lib/insika/model_visible_trace_store.rb', line 24

def record(task_id:, turn:, part: "turn", payload:)
  return nil if payload.nil?

  @store.set(SCOPE, key(task_id, turn, part), payload.to_h)
  payload
rescue StandardError
  nil
end