Module: Insika::Evidence

Defined in:
lib/insika/evidence.rb

Overview

— the evidence contract (engine half).

A tool DECLARES evidence in its manifest; the engine then does BOTH jobs from the same declaration: strips the result down to {items: [{id, line}]} for the model (the lean envelope), and appends every id to the session evidence ledger. No second flag, no "lean but not evidence" mode — a half-configuration cannot exist, which is what keeps "no claim without a tool ID" a tautology at the envelope instead of a convention.

Everything here is pure Ruby, no IO: the ToolEnvelope calls it after the real tool returns. It does NOT write anything — the ledger write is the envelope's, via the state.

Defined Under Namespace

Classes: Processor, Spec

Constant Summary collapse

MAX_ITEMS =

The lean result the model sees — the ONLY thing that survives the envelope.

16
LINE_MAX =

Line truncation keeps the transcript lean by force (E1).

200
MAX_ATTACHMENTS =

Attachments are a channel nicety, never the answer; bounded on purpose.

16
URL_MAX =
500

Class Method Summary collapse

Class Method Details

.valid_attachments(list) ⇒ Object

The attachments contract, validated for the outbox (channel side, never the model): [{ "type" => "card"|"image", "url" => String, "caption" => String|nil }]. Entries without a String url, or beyond MAX_ATTACHMENTS, are DROPPED — never a turn failure (the card is a channel nicety, not the answer).



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/insika/evidence.rb', line 73

def self.valid_attachments(list)
  Array(list).filter_map do |entry|
    next unless entry.is_a?(Hash)

    url = (entry["url"] || entry[:url]).to_s
    next if url.empty?

    caption = Coercion.presence(entry["caption"] || entry[:caption])
    { "type" => (entry["type"] || entry[:type]).to_s,
      "url" => url[0, URL_MAX],
      "caption" => caption }
  end.first(MAX_ATTACHMENTS)
end