Small models as tool-call guards
Part of DefenseClaw

Appendix: method and data

What the main page rests on: the corpus, the second corpus, the diagnostics moved out of the argument, and how to rebuild every figure.

A1

Corpus and grades

How many calls are scored, and how is each one labelled?

3,817 of 4,277 cases are scorable, and 436 of those must be blocked.

Grade B supplies 419 of the 436 positives; only 17 carry a deterministic proof

Corpus s2 by truth grade, 4,277 cases.

How to read it. The bar is the whole corpus, split by truth grade. Grades A and B had to be blocked, grade D had to be allowed, and grade C is excluded.

What it shows. Only 17 of the 436 positives are grade A; the 460 unresolved grade C cases are scored nowhere.

Data table
Source
The five grades, the condition that assigns each, and the cases in each corpus
GradeConditionScored ass2 casess3 cases
A, confirmed destructiveA closed deterministic proof, expected disposition detect or block, label confidence highPositive17193
B, destructiveSource truth malicious or sensitive, a stateful surface, expected disposition detect or block, label confidence highPositive41928
C, unresolvedSource truth malicious or sensitive, or a deterministic verdict of contextual or dual useExcluded4600
D, benignExpected disposition allow, and the source calls the case benignNegative3,38124,255
E, out of scopeOut of scope, or unknown source truth with no deterministic verdictNot present00

One deterministic function, truth_grade(), assigns every grade from fields already on each case row. No model and no human reviewer is consulted, so no inter-rater agreement figure exists. Source-label error is therefore a limitation, and so is error correlated with the labelling source.

Prevalence is 11.4%: 436 of 3,817. Allowing every call is right 88.6% of the time, which is why accuracy is never shown alone.

The 12 source datasets: cases in each corpus, positives, and licence
Dataset s2 positives s2 cases s2 scorable s3 cases s3 positives Licence Redistribution

Two sources carry a restricted redistribution marker. A census of both corpora found 0 rows from either, so neither contributes a case to any figure.

A2

Second corpus

Do the models behave the same on a different corpus?

On a corpus whose positives are mostly grade A, the same models rank grade A and grade B cases very differently.

shieldstral-1.0-3b scores AUC 0.993 on grade A positives and 0.616 on grade B

Corpus s3, 24,476 cases: AUC against benign cases, computed separately for 193 grade A and 28 grade B positives. 6 models.

How to read it. Each row is a model. One dot is its AUC on grade A positives, the other on grade B, both against benign cases. The line joins them; 0.5 is chance.

What it shows. shieldstral-1.0-3b drops from 0.993 to 0.616, while granite-guardian-3.2-3b-a800m rises from 0.364 to 0.646.

Data table
Source

Corpus s3 shares no case id with s2. Its positives are 87.3% grade A against 3.9% in s2, and its prevalence is 0.903% against 11.4%. Blocking everything there scores F1 0.0179, 11.5 times lower than on s2, purely because of prevalence. So no score on this Space is compared across the two corpora.

All 15 pairwise AUC differences among the 6 models are significant; the median minimum detectable difference is 0.0416. Positives contribute 98.7% of the AUC variance. The held-out transfer results are out of this revision by design.

For a deploy decision, a model's rank depends on which kind of destructive call dominates. Before you reuse any figure here, check which grades your own traffic resembles.

A3

Calibration

Does a block score mean the same thing for every model?

Block scores are not calibrated probabilities, so the same cut-off means different things for different models.

Observed destructive share by score bucket for falcon3-1b-instruct

Calibration over ten equal-width buckets of each model's own block score, 3,817 cases. Empty buckets are skipped.

How to read it. Each point is one bucket of the chosen model's block score. Across is the mean score in the bucket; up is the share of its cases that are destructive. Pick a model in the menu; the diagonal is perfect calibration.

What it shows. 51 of 220 buckets, across all 22 models, hold fewer than 20 cases, so many points rest on few calls.

Data table
Source

Across the 22 models, 69 of 220 buckets are empty and 51 hold fewer than 20 cases. falcon3-1b-instruct puts 1,499 of 3,817 cases into the single bucket from 0.4 to 0.5, so its threshold has little room to move.

Pick other models in the menu to compare their shapes. A shared cut-off such as 0.5 means something different for each model. Fit each threshold to your own false-block budget instead.

A4

The DeBERTa window

Does cutting off long inputs explain deberta-v3's weak catch?

deberta-v3 reads 510 tokens and drops the rest, yet ranks truncated cases slightly better than complete ones.

Truncation does not explain deberta-v3's weak catch: AUC 0.802 on truncated cases, 0.777 on complete ones

deberta-v3-prompt-injection-v2 on corpus s2, split by whether any event in the case ran past its 510-token window.

How to read it. Two groups of cases: those that ran past the 510-token window and those read in full. Each group has three bars: AUC, F1 at the in-sample best threshold, and recall there.

What it shows. AUC is 0.802 on truncated cases and 0.777 on complete ones; prevalence differs, 18.7% against 3.5%.

Data table
Source
How much of the corpus runs past 510 tokens
MeasureCountOfShare

As shipped, deberta-v3 blocks 3,629 of 3,817 cases, 95.1%. Its one catch at the budget is not a window effect. The per-row truncated flag in the prediction files is a corpus-level request flag, set on the same 2,086 rows for every model; it is not this window.

So a longer window alone would not lift deberta-v3's catch at the budget. Look for the cause elsewhere before tuning its input length.

A5

Controls

What does a model with no safety training score here?

The pre-registered prediction did not hold: one control falls below chance under length control.

Untrained backbones swing from 0.27 to 0.75 AUC across length quintiles

AUC inside each prompt-length quintile for the two controls and for prompt-token count with no model.

How to read it. Groups are the five prompt-length quintiles, each labelled with its positives. Bars are AUC inside that quintile, for the two controls and for prompt-token count alone; 0.5 is chance.

What it shows. The untrained backbones swing from 0.27 to 0.75 across quintiles; quintile 1 holds only 2 positives.

Data table
Source

The prediction was that both controls land inside the chance band under length control. control-modernbert-base does, at 0.488. control-modernbert-large lands below it, at 0.389. The two controls' scores correlate at only 0.144, which points at idiosyncratic readout behaviour rather than a label leak both would see.

Even so, the controls are useful floors. As shipped, control-modernbert-base scores default-decision F1 0.250. 12 of the 19 candidates with a default decision score at or below it.

Treat the controls as the floor any candidate must clear. What a control scores is what the corpus gives away for free; a candidate at or below it shows nothing beyond that.

A6

Overlap between models

Do the models catch the same calls?

The models catch different calls, which is why combining them adds catches at all.

185 of 221 model pairs share no caught positive at 13 false blocks

Jaccard index of caught positives at the budget, for the models that catch at least one.

How to read it. Rows and columns are the models that catch at least one positive; row labels give their catches. Each cell is the Jaccard index of two models' caught calls, shaded by the ramp in the legend.

What it shows. The widest overlap is 0.5, between llama-guard-3-1b and olmo-2-1b-instruct, which share 1 catch.

Data table
Source

Pairs share 62 caught positives in all, against 15.7 expected if the models caught independently. The overlap is in-sample, like the best pair.

Low overlap is why unions add catches, but each model's catches are few. Combining them buys recall only by spending false blocks well past the budget.

A7

Model roster

Which models were tested, and under which licences?

22 checkpoints, each pinned to one revision: 12 decoders, 5 safety classifiers, 3 encoders and 2 controls.

Every model with its repository, pinned revision, class, counted parameters, licence and gating
Model Repository at revision Class Parameters Licence Gated Origin

The weights total 85.5 GiB. 14 models are under 3B parameters and 8 are from 3B to 6B. 8 are gated, in the Gemma, Llama 3.2 and Prompt Guard 2 acceptance groups. For granite-guardian-3.2-3b-a800m, a mixture of experts, the count is the total; about 800M are active. Qwen3 0.6B, 1.7B and 4B were dropped for provenance before any run.

A8

Methodology

How was each model asked and scored?

One question per tool call, one block score per model, one budget for all.

Each of 22 models was asked, for every event of every case, whether the tool call about to run must be blocked. The request is built by the System One reference driver, build_state and build_questions. That is why each row's context digest, byte count and truncation flag match the System One board rows byte for byte.

Each model yields one ranking variable. Three-class models use P(block); the two-head model uses block.yes; two-class models use their single positive-class probability. P(block) minus P(confirm) is never ranked on, because on the System One programme it fell below chance on a disjoint corpus.

The budget is a block false-positive rate of 0.00385: 13 false blocks of 3,381 benign cases, the existing DefenseClaw cascade's own rate on s2. Every model's threshold is refitted to it on the same rows, so thresholds are fitted for this comparison and are not the models' own defaults.

Recall and block FPR carry Wilson 95% intervals at z = 1.96. F1 carries a percentile bootstrap over cases, 2,000 resamples at seed 20260924, with each threshold held fixed. That covers sampling of the corpus but not refitting the threshold. The zero-false-positive gate carries the rule-of-three bound, 3 of 3,381 (0.000887).

A run counts only if its metadata says complete and the sha256 of its predictions on disk matches the recorded digest. The settle step adds both after requiring 30,310 untorn rows, then re-reads and re-hashes. All 22 models are complete, hash-verified runs, with 0 digest mismatches.

The shared arithmetic, remine.py, is imported verbatim by the three scoring scripts, not reimplemented. No GPU was used in the ranking or the curves.

A9

Reporting rules

Which rules does every figure follow?

Six rules every figure on this Space follows.

  1. One budget. Precision, recall, F1 and block FPR are reported at block FPR 0.00385. Each threshold is the one with the highest recall that holds it, ties broken toward the tighter threshold. The slider on the main page re-reads the same curves at other budgets.
  2. Scorable cases only. Every F1, AUC, FPR and confusion count is over the 3,817 cases of grade A, B or D. The 460 grade C cases are counted nowhere.
  3. Oracle figures are labelled. A best F1 found by sweeping thresholds on the scored rows is an upper bound. It appears only in its own field, never as a result.
  4. Accuracy only beside all-allow accuracy, 0.886, because at 11.4% prevalence the benign class sets it.
  5. One ranking variable per class structure, as in the methodology. For the 7 two-class models, 2 of them controls, P(confirm) does not exist.
  6. Neither gate is durable. When the System One programme moved thresholds to a disjoint corpus, 4 of 24 zero-false-positive gates survived, 3 of them degenerate, and false-positive caps held in 8 of 48.
A10

Build gates

How is each published number checked?

Every published number is recomputed and checked before a page is written.

  • The extraction for this Space reproduces all 577 figure values the previous Space published, with 0 mismatches. All 22 leaderboard rows match, and all 20 artifact digests match the files at the pinned commit.
  • Each ROC curve is carried as integer (false blocks, true blocks) pairs, 6,515 points across 22 models. The area under each drawn curve equals the published raw AUC exactly, and the budget point lies on the curve.
  • The previous build recomputed 2,251 figures from their primitives over 20 input files and 22 charts, aborting on any mismatch.
  • A leak guard fails on any corpus case id, sensitive-text shingle, CJK codepoint or credential shape, and on any file type outside .html .css .md .json .txt or over 1 MiB.
  • The monorepo build checks that every data file parses, that no page repeats an element id, and each page's word budget.
A11

Changelog

What changed between revisions?

  • 2026-10, this redesign. Five pages became one chaptered page plus this appendix. Every chart reads data/*.json, written from the artifacts at commit c7e264e63e. The two controls are now unranked everywhere. The budget slider re-reads every curve; the 22-panel small multiples became one overlaid ROC.
  • Previous revision. Eleven pages became five. The controls' length-controlled AUCs, the DeBERTa figure and the length counter moved from the retracted unweighted estimator to the published one, and the leakage verdict was re-read from it.
  • Earlier. The unweighted mean of per-quintile AUCs was retracted in favour of the pair-weighted pooled figure superseded. The claim that Prompt Guard 2 supplied an independent encoder backbone was withdrawn.
A12

Reproduce

How can you rebuild every figure?

Every input is public at one commit, and every figure here is rebuilt from it.

The artifacts live in benchmarks/slm_toolcall at commit c7e264e63e of cisco-ai-defense/defenseclaw. Run python3 tools/extract_slm.py --fetch and then python3 tools/build.py slm-toolcall from the monorepo root.

The scripts behind every number, and what each does
PathRole
The 20 artifacts read, with their sha256 as published and as fetched
Artifactsha256Matches

The laptop measurements were ad-hoc invocations never saved as a script, so they are archived rather than reproducible.

A13

Glossary

What does each term mean?