Module: Vangrail::EvidenceData
- Defined in:
- lib/vangrail/evidence_data.rb
Overview
What each rail is worth as evidence, measured on corpora written by other people.
GENERATED FILE. Do not edit by hand; rerun script/measure_evidence_external.rb.
Rerunning does not check these numbers, it replaces them. The benign context population is whatever documentation is installed on the machine that runs the script, globbed out of /usr/share/man and /usr/share/doc, so it is a package set at a moment and not a corpus anybody can obtain. One machine offered 69227 candidate files against the 18258 below. The published attack corpora are hash-pinned in evaluation/benchmark_sources.json and fetch reproducibly; the benign context side is the half that does not.
So a rail whose behaviour moved cannot be found here: the corpus varies by more than the rail would. What finds that is the per-rail counts pinned against the sixty poisoned cases and fifteen benign pages this repository ships, which are reproducible anywhere. The arithmetic that reads this table lives in evidence.rb, which is hand-written and survives regeneration.
One benign source per side; the attack population is stated.
Context: 125 published BIPIA injections spliced into installed documentation, plus 120 attacks from this repository's own corpus, against 18258 real documents from the same machine. Two attack families on purpose: BIPIA's off-task instructions, which no deterministic rail here catches, and the override-and-disclosure family the rails were built for, which the shipped corpus covers and which nobody else's benchmark does. The ratio is 125:120 and a deployment whose traffic is not that mix should reweight it and rerun the script.
Input: 1405 in-the-wild jailbreak prompts against the 13735 ordinary prompts collected beside them.
Read the context numbers before trusting anything built on them. Every deterministic rail catches none of the published injections, because BIPIA's attacks are off-task instructions carrying no override, no disclosure, and no concealment, and those three are all these rails know how to find. A rail that fires on a document under this measurement is reporting a false alarm more often than an attack, and the sign of its evidence says so.
That is a statement about a threat model, not a verdict on the rails: the corpus this repository wrote scores them at 60 of 60, because it was written out of the same idea of an attack. Both numbers are real and neither is the answer on its own.
Constant Summary collapse
- CONTEXT =
[ Evidence.new(rail: "injected_instructions", group: "injected_instructions", attacks_caught: 58, attacks: 245, benign_flagged: 48, benign: 18258), Evidence.new(rail: "jailbreak", group: "jailbreak", attacks_caught: 10, attacks: 245, benign_flagged: 20, benign: 18258), Evidence.new(rail: "paraphrase", group: "paraphrase", attacks_caught: 61, attacks: 245, benign_flagged: 236, benign: 18258), Evidence.new(rail: "alignment", group: "alignment", attacks_caught: 12, attacks: 245, benign_flagged: 24, benign: 18258), Evidence.new(rail: "similarity", group: "similarity", attacks_caught: 12, attacks: 245, benign_flagged: 0, benign: 18258), Evidence.new(rail: "many_shot", group: "many_shot", attacks_caught: 0, attacks: 245, benign_flagged: 2, benign: 18258), Evidence.new(rail: "obfuscation", group: "obfuscation", attacks_caught: 60, attacks: 245, benign_flagged: 59, benign: 18258), Evidence.new(rail: "hidden", group: "hidden", attacks_caught: 5, attacks: 245, benign_flagged: 0, benign: 18258), Evidence.new(rail: "bayes", group: "bayes", attacks_caught: 100, attacks: 245, benign_flagged: 1617, benign: 18258) ].freeze
- INPUT =
[ Evidence.new(rail: "injection_patterns", group: "injection_patterns", attacks_caught: 35, attacks: 1405, benign_flagged: 730, benign: 13735), Evidence.new(rail: "jailbreak", group: "jailbreak", attacks_caught: 190, attacks: 1405, benign_flagged: 134, benign: 13735), Evidence.new(rail: "paraphrase", group: "paraphrase", attacks_caught: 486, attacks: 1405, benign_flagged: 1666, benign: 13735), Evidence.new(rail: "alignment", group: "alignment", attacks_caught: 160, attacks: 1405, benign_flagged: 998, benign: 13735), Evidence.new(rail: "similarity", group: "similarity", attacks_caught: 127, attacks: 1405, benign_flagged: 857, benign: 13735), Evidence.new(rail: "many_shot", group: "many_shot", attacks_caught: 10, attacks: 1405, benign_flagged: 34, benign: 13735), Evidence.new(rail: "obfuscation", group: "obfuscation", attacks_caught: 248, attacks: 1405, benign_flagged: 440, benign: 13735), Evidence.new(rail: "bayes", group: "bayes", attacks_caught: 340, attacks: 1405, benign_flagged: 1715, benign: 13735) ].freeze
- ENTRIES =
(CONTEXT + INPUT).freeze
- BY_SIDE =
{ context: CONTEXT.to_h { |entry| [entry.rail, entry] }.freeze, input: INPUT.to_h { |entry| [entry.rail, entry] }.freeze }.freeze
- TABLE =
A rail's operating point depends on which side it runs on, by a lot: the same rail is worth different evidence reading a retrieved document and reading a question. The default is the input table because that is the side with a detection measurement worth having.