# Guardrail detectors — the inventory

Every detector this build registers, with its category, locality, phases, and version — with activation restrictions and categories without production coverage.

Source: https://tokentriage.com/docs/reference/guardrail-detectors

---
import Callout from '../../../components/Callout.astro';
import Details from '../../../components/Details.astro';
import NextSteps from '../../../components/NextSteps.astro';

This page lists **registered detector contracts and declared phases**. Registration alone does
not establish activation support or measured detection quality. The three
companion pages answer **"what will it miss?"** in full:
[PII detectors](/docs/reference/guardrail-detectors-pii) and
[secrets & injection detectors](/docs/reference/guardrail-detectors-secrets-injection) and
[toxicity, topical, code & media detectors](/docs/reference/guardrail-detectors-content).

<Callout type="key">
The binary is the source of truth, not this page. `tokentriage guardrails list` prints every
detector's `covers` and `NOT covered` **at the version you are actually running**, and a test in
the product repo compares the operator guide against that output. Where the two disagree, the
binary is right. The inventory below reflects the current registrations; **counts drift with
the build**. Historical fixture figures on companion pages retain their original scope.
</Callout>

## The registry

**21 registered detectors across 7 categories: 17 embedded and 4 external**, plus **1 `drill` stub** that is listed and explicitly
**not counted as coverage** — it exercises the machinery, not a category.

### `pii` — nine embedded detectors

| id | locality | phases | version |
|---|---|---|---|
| `pii.card` | `embedded` | input, output, stream | `pii.card-v1` |
| `pii.crypto` | `embedded` | input, output, stream | `pii.crypto-v1` |
| `pii.email` | `embedded` | input, output, stream | `pii.email-v1` |
| `pii.iban` | `embedded` | input, output, stream | `pii.iban-v1` |
| `pii.ip` | `embedded` | input, output, stream | `pii.ip-v1` |
| `pii.mac` | `embedded` | input, output, stream | `pii.mac-v1` |
| `pii.nationalid` | `embedded` | input, output, stream | `pii.nationalid-v1` |
| `pii.phone` | `embedded` | input, output, stream | `pii.phone-v1` |
| `pii.ssn` | `embedded` | input, output, stream | `pii.ssn-v1` |
| `sidecar.ner_pii` | `sidecar` | input, output | `sidecar.ner_pii-v1` |

The nine embedded ones cover **structured formats only** — a shape with a checksum or a fixed
grammar. Names, street addresses and organizations have no such shape; that is what
`sidecar.ner_pii` is intended to classify. Its stock activation is rejected pending runtime/model
qualification; this registration establishes no current NER efficacy.
[Read each one's gaps →](/docs/reference/guardrail-detectors-pii)

### `secrets`, `injection`, `toxicity`, `topical`, `code`, `multimodal`

| id | category | locality | phases | version |
|---|---|---|---|---|
| `secrets.entropy` | `secrets` | `embedded` | input, output, stream\* | `secrets.entropy-v2` |
| `secrets.generic` | `secrets` | `embedded` | input, output, stream\* | `secrets.generic-v2+glb58d3f102cf3.…` |
| `secrets.ruleset` | `secrets` | `embedded` | input, output, stream\* | `secrets.ruleset-v3+glb58d3f102cf3.…` |
| `injection.heuristic` | `injection` | `embedded` | input, output | `injection.heuristic-v1` |
| `injection.judge` | `injection` | `judge` | input | `injection.judge-v1` |
| `sidecar.injection` | `injection` | `sidecar` | input | `sidecar.injection-v1` |
| `toxicity.wordlist` | `toxicity` | `embedded` | input, output | `toxicity.wordlist-v1` |
| `sidecar.safety` | `toxicity` | `sidecar` | input, output | `sidecar.safety-v1` |
| `topical.keywords` | `topical` | `embedded` | input, output | `topical.keywords-v1` |
| `code.patterns` | `code` | `embedded` | **output only** | `code.patterns-v1` |
| `media.inventory` | `multimodal` | `embedded` | **input only** | `media.inventory-v1` |

\* The three `secrets.*` detectors **declare** the stream phase but implement no incremental
matcher. A stream binding naming one is *accepted* at boot, contributes no lane at run time,
discloses `stream_unsupported`, and applies the effective mode and failure posture. The stock
gateway rejects `stream_fallback: buffer`; acknowledged enforcing/closed withholds unreleased bytes.
[Secrets & injection gaps →](/docs/reference/guardrail-detectors-secrets-injection) ·
[toxicity, topical, code & media gaps →](/docs/reference/guardrail-detectors-content)

### The stub

| id | category | locality | phases | version |
|---|---|---|---|---|
| `drill.echo` | `custom` | `embedded` | input, output, stream\* | `drill.echo-v1` |

<Callout type="warning">
**`drill.echo` is not coverage.** It matches one exact literal planted secret, byte for byte, and
exists to exercise the machinery end to end. It is listed by `guardrails list` and explicitly
excluded from the detector count. Binding it protects nothing.
</Callout>

## Categories without production coverage

`custom` has only the `drill.echo` test stub. A binding with an empty detector list is rejected,
and a binding's category must match its registered detectors. Naming a vocabulary member does not
create a detector or establish coverage.

`format` registers one detector as a **factory row**, not a ready instance:

| id | category | locality | phases | version |
|---|---|---|---|---|
| `format.jsonschema` | `format` | `embedded` | **output only** | `format.jsonschema-v1` (a live instance appends `+cfg<sha7>` over its schema bytes) |

It validates a response field against a JSON Schema document the workspace supplies on the
binding — there is no schema-less form, so `guardrail.Detector(id)` answers not-ok until a binding
configures one, and `guardrails list` (and so the count above) does not show it until it is
configured on at least one binding. [Check a response against a JSON
schema](/docs/guardrails/response-schema) is the configuration page and the limits that apply to
the schema itself.

<Callout type="key">
The category vocabulary is the closed set **the ledger speaks**. A Go embedding can register its
own detector under `custom`; the stock stub does not protect a real content category.
</Callout>

## Phases: refused at boot vs. degraded at run time

These are two different failures and operators regularly expect the wrong one.

| what you wrote | what happens |
|---|---|
| A detector that **does not declare** the phase — `code.patterns` on `stream`, `media.inventory` on `output` | **Refused at boot.** Config validation and `guardrail.Compile` both reject it. The process does not start, and no row is ever written to carry a fallback disclosure. |
| A detector that **declares** the phase but implements no incremental matcher — any `secrets.*` on `stream` | **Accepted with supported fallback syntax, disclosed at run time.** No incremental lane is available; `stream_unsupported` applies the selected mode/posture. Stock `buffer` activation is rejected; enforcing/closed withholds unreleased bytes. |

The first is the correct failure and not the one most operators expect: being told the wrong
failure mode is what ships a config that will not boot. See
[Phases & streaming](/docs/guardrails/phases-and-streaming).

## Locality — which detectors leave the box

| locality | what it is | leaves the process? |
|---|---|---|
| `embedded` | pure Go, in-process | **no — ever.** The subtree is import-restricted and swept by a test |
| `judge` | an LLM call to a configured judge model | **yes** |
| `sidecar` | an HTTP call to a model sidecar you run | **yes** |

Embedded detection makes no model call. Primary-provider traffic and other enabled services have
their own network boundary; choosing embedded detectors alone does not prove process isolation.

<Callout type="warning">
**Stock sidecar activation is rejected pending runtime/model qualification.** A supported input
judge requires destination consent. A positive hard dollar cap is rejected without a proven
conservative reservation price; an explicit zero cap permits configuration but sends no judge
calls. Independent invocation receipts retain actual-send state, safe identities and priced or
explicitly unpriced cost even when no finding is produced. See
[the external tiers](/docs/reference/guardrail-detectors-secrets-injection#the-external-tiers).
</Callout>

## Caveats that apply to a whole family

Rather than repeat these on nine detectors, they are stated once. Every one of them is printed
per detector by `guardrails list`.

<Details summary="The nine embedded pii.* detectors share these bounds">

- **Per field, not per document.** A value split across a *message* boundary — halves in
  `messages[0]` and `messages[1]` — is never reassembled. Cross-message cases are misses and are
  reported as misses.
- **128 KiB of inspected text in total.** A document exceeding it is **refused and disclosed as
  `detector_error`**, never silently truncated.
- **De-obfuscation is bounded.** The invisible-character set is a Unicode *property* test (Cf and
  Mn) plus the variation-selector supplement plus a deliberately **incomplete** enumeration — an
  invisible rune outside those is a miss. The confusables fold is not a full TR39 skeleton:
  single-rune-to-single-byte mappings only, because multi-character mappings would break the byte
  correspondence the span contract rests on.
- **Base64 payloads** are decoded one level, when the encoded run is at least 12 characters. Hex,
  rot13, URL-encoding and nested double-encoding are not decoded.
- **The streaming lane has three separate bounds** and only one of them is about the value. See
  [Phases & streaming](/docs/guardrails/phases-and-streaming) for the measured ladder.
- **A calibrated bound changes what `threshold` means.** While an artifact licenses a detector
  version, `threshold` and `severity_bands` read the licensed point instead of the raw signal —
  so the ladder collapses to one rung and the units change from *signal strength* to *this
  version's estimated precision*. Four of the nine (`pii.card`, `pii.crypto`, `pii.iban`,
  `pii.mac`) never spend a calibrated bound at all, because every rule they carry is an exact
  match.

</Details>

<Details summary="The three sidecar.* registrations share these limits">

- **Stock activation is unavailable.** The reference protocol and synthetic transport tests do not
  qualify the model runtime or establish detector efficacy.
- **A verdict is a raw model score**, with `basis: reported` and no calibrated interval.
- **A field over 32 KiB refuses the scan**, with a disclosed suspension instead of a verdict on a
  truncated prefix. The adapter sends decoded text, not media parts.
- **In a custom Go embedding**, unavailable calls produce failures whose consequences depend on
  mode and failure posture. An enforcing/closed policy can refuse; monitor preserves traffic.
- Model identity and operator license metadata do not verify model quality or license compliance.

</Details>

## How to read a measured figure here

<Callout type="warning">
**Below a denominator of 20, the harness refuses to render a rate as a decimal — and so do these
pages.** `pii.ssn`'s efficacy rests on **10 positives**; `pii.iban`'s and `pii.phone`'s on **6**.
Those are printed as tallies with their denominators, never as percentages. A perfect tally on a
small corpus is the most quotable and least honest number this layer could emit.
</Callout>

Two further reading rules, both from the detectors' own disclosures:

- **A corpus its own author wrote certifies its own work.** `code.patterns`, `toxicity.wordlist`
  and `topical.keywords` are scored against fixtures written by the card that shipped them. That
  is exactly why their confidence basis stays `reported` and is never minted as `fixture`.
- **`injection` never carries an interval, at any basis.** It is the one *adversarial* category in
  this build: attacker-chosen traffic is out-of-distribution by intent, so the exchangeability a
  conformal or binomial bound assumes is false for it. This is a rule, not a gap awaiting work.

<NextSteps items={[
  { title: "PII detectors in detail", href: "/docs/reference/guardrail-detectors-pii", description: "All nine, with what each one covers and — at equal length — what it misses." },
  { title: "Secrets & injection detectors", href: "/docs/reference/guardrail-detectors-secrets-injection", description: "The secrets family's three-way split, the injection floor, and the two external tiers." },
  { title: "Toxicity, topical, code & media", href: "/docs/reference/guardrail-detectors-content", description: "The wordlist, the topic scaffold, the code tripwire, and the media presence gate." },
  { title: "Guardrail vocabularies", href: "/docs/reference/guardrail-vocabularies", description: "Every closed enum in one place: categories, phases, modes, verbs, effects, suspension reasons, bases." }
]} />
