Class: Insika::Safety::GroundingValidator
- Inherits:
-
Object
- Object
- Insika::Safety::GroundingValidator
- Defined in:
- lib/insika/safety/grounding_validator.rb
Overview
— the :flag half of grounding. A reply claiming a product
whose reference is not in the evidence ledger is FLAGGED (audit via the
existing :guardrail_flagged channel) — the text is already out, so
flagging is audit, exactly like every other output flag.
Runs as the FIRST step of the OutputValidator's after_task chain, BEFORE
the config.output gate (D9): grounding is evidence integrity, independent
of the guardrails opt-in — an agent with guardrails off and
grounding.mode: :flag still gets the check. Fail-open on any error
(grounding must never break a completed turn).
Instance Method Summary collapse
-
#call(state) ⇒ Object
-> state (the after_task contract).
Instance Method Details
#call(state) ⇒ Object
-> state (the after_task contract). Appends :ungrounded flags.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/insika/safety/grounding_validator.rb', line 17 def call(state) grounding = grounding_of(state) # :flag only — :enforce is the enforcer's job, :off / absent is nothing. return state if grounding.nil? || grounding.off? || grounding.enforce? ledger = state.respond_to?(:evidence_ledger) ? state.evidence_ledger : nil return state unless ledger text = state.response_content.to_s return state if text.empty? refs = grounding.matcher.references(text) claims = grounding.matcher.ungrounded(refs, evidence_ids: ledger.ids) claims.each { |c| ledger.ungrounded_count(c) } unless claims.empty? state.guardrail_flags = Array(state.guardrail_flags) + [{ category: "ungrounded", source: "evidence", detail: "product claim without tool evidence: #{claims.join(', ')}" }] end state rescue StandardError state # fail-open end |