# PII input guardrails

TnsAI 0.14.0 (`@since 0.14.0`). TnsAI
[PR #168](https://github.com/TnsAI-Framework/TnsAI/pull/168)
(`81b2fb95`, TAN-3016) adds executable `@InputGuardrail` validators and
sanitizers, including built-in PII detection. This ships in Maven
Central `0.14.1`.

This page is **action input**. It is not
`com.tnsai.quality.tracing.guardrail.PiiGuardrail` (traced content
scoring — [Guardrails](guardrails.md)) and not the output
[Redaction](redaction.md) SPI. Approval-token lifecycle is TAN-5857.

## Annotation-first setup

```java
import com.tnsai.annotations.InputGuardrail;
import com.tnsai.guardrails.pii.PiiInputSanitizer;
import com.tnsai.guardrails.pii.PiiInputValidator;

@InputGuardrail(
        validators = PiiInputValidator.class,
        sanitizers = PiiInputSanitizer.class,
        onFailure = InputGuardrail.FailureAction.SANITIZE)
public String handleContact(String message) {
    return message;
}
```

Both types need a public no-arg constructor. Applications may supply
their own `InputValidator` / `InputSanitizer` implementations.

There is no `FailureAction.REDACT`. Redaction is `SANITIZE` plus
`PiiInputSanitizer`.

## Heuristic classes

Detection is high-precision and **not** a legal or jurisdiction-complete
classifier. Raw matches stay in the current call and are not written into
diagnostics.

| Class | Token |
|---|---|
| Practical email shape | `[REDACTED_EMAIL]` |
| International prefix or 10-digit local phone | `[REDACTED_PHONE]` |
| IBAN country/check-digit shape (compact length 15–34) | `[REDACTED_IBAN]` |
| Luhn-valid 13–19 digit payment-card shape | `[REDACTED_PAYMENT_CARD]` |
| US SSN shape | `[REDACTED_NATIONAL_ID]` |
| Checksum-valid 11-digit Turkish identity | `[REDACTED_NATIONAL_ID]` |

`PiiInputValidator` rejects when any class matches. It also inspects
**parameter names**.

## `onFailure` dispositions

Default is `REJECT`.

| Value | After a validator rejects |
|---|---|
| `SANITIZE` | Run declared sanitizers in order, then re-validate |
| `REJECT` | Throw `GuardrailViolationException` (`INPUT_VALIDATOR_REJECTED`) |
| `REVIEW` | Throw `GuardrailViolationException` (`NEEDS_REVIEW`) |
| `WARN` | Log and continue without rewriting |

Containers, nested objects, custom-rendering enums, and custom number
types fail closed — a type-preserving rewrite is not guaranteed. Flatten
those payloads first. Runtime `String` values declared as `Object` are
inspected. Booleans, default-rendering enums, and exact immutable JDK
numbers use stable textual forms.

## Production order

`ActionExecutor` on PR #168:

1. Access control
2. `@BeforeAction` on plaintext
3. `InputGuardrailEnforcer` (PII lives here)
4. Optional security encryption of parameters
5. Action / LLM / tool / MCP body

Encryption after the guardrail is required. Ciphertext would hide PII
from validators or fail a second pass.

The same enforcer covers Role actions, generic Object/SCOP dispatch,
static `@Tool` methods, and MCP-exposed tools.

## Bounded regex subset

The **1,024-character** caps apply to `blockPatterns` / `allowPatterns`
and the inspected input, not to the built-in PII `Pattern`s.

Before matching, the enforcer rejects backreferences, nested
quantifiers, comments mode (`x`), multi-token escapes, more than one
non-fixed non-possessive backtracking quantifier, and more than one
alternation group. Fixed repetitions and possessive quantifiers may
repeat. One non-capturing alternation group, lookarounds, other inline
flags, and lazy/possessive modifiers remain allowed.

## Related

- [Guardrails](guardrails.md) — three APIs that share the name
- [Redaction](redaction.md) — output `Redactor` SPI
- TAN-3016 / TnsAI #168 — implementation
- TAN-5863 — this documentation
- TAN-5857 — approval-token follow-up
