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
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
-
.valid_attachments(list) ⇒ Object
The attachments contract, validated for the outbox (channel side, never the model): [{ "type" => "card"|"image", "url" => String, "caption" => String|nil }].
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.(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 |