TurfAITurfAI User Guide
Modules

Data Shield

Tokenise PII before content reaches an LLM.

Status: Limited GA (v0.5). Data Shield tokenises 8 structured PII types (L1, regex + format validation) across 3 LLM entry points. Free-text names/locations/orgs, RAG chat, file contents, and a customer-held key are not in v0.5 — they ship in v1.0+. Read Limitations (v0.5) before relying on it for a compliance attestation.

What it is

Data Shield tokenises PII before a workflow, agent, or extraction call reaches the underlying LLM provider. The LLM sees opaque tokens (EMAIL_84d0a133, SSN_c95eb795); the caller sees the original values restored in the response. Every event is recorded in an immutable audit log with entity counts per type — never raw values.

Tokenisation is deterministic within a request scope and isolated across scopes:

  • Within one call the same raw value always maps to the same token, so the LLM reasons about "the customer" coherently across messages in that call.
  • Across calls (and across tenants) the same value maps to a different token — there is no cross-call or cross-tenant token reuse. The scope key is {tenant_id}:{scope_type}:{scope_id}, so tenant isolation holds by construction.

In v0.5 the scope is per-request and ephemeral — the token map lives in memory for the duration of one request and is destroyed when the request frame ends. There is no on-disk token map, and no customer-held key yet. Consistency across documents or sessions requires the v1.0 KMS-backed persistent scope (see roadmap).

When to use it

Turn it on for any LLM step that may see personal or sensitive data — extraction over identity documents, agents handling customer records, free-form LLM tasks on user content. It is a core governance control.

Data Shield is opt-in and off by default. Decide deliberately:

  • Enable per node when one specific llm_task / agent_task touches PII.
  • Require per workflow when every LLM node in a sensitive workflow must be shielded and you want the executor to fail the run if an author forgets. Use this for regulated workflows (insurance, legal, financial) where a single un-shielded node is a breach.
  • Set per pack when a Solution Pack should ship the policy so every instantiated workflow inherits it.

How it works

Process flow — tokenise, call, restore:

Call flow — through the gateway:

Sub-features

  • L1 detection across 8 entity types: EMAIL, PHONE, SSN, CREDIT_CARD, IP, AADHAAR, PAN, IBAN.
  • Three opt-in scopes — per-node, per-workflow (require on every LLM node), per-pack (manifest policy).
  • Audit log — counts by type, layers invoked, stage latencies, retention timestamp, correlation id; immutable after write.
  • Kill switches — disable gateway or audit; tune retention.
  • Recall-biased detectors — tuned to over-tokenise rather than miss (a false positive is restored on the return path; a false negative is a leak).

Configuration parameters

The three opt-in scopes

ScopeWhere you set itEffect
Per-nodeWorkflowBuilder → select an llm_task / agent_task → "Data Shield" card → flip the switchTokenises that node's LLM calls. Optionally restrict to a subset of the 8 types via the chip row.
Per-workflowWorkflowBuilder → Resilience tab → "Data Shield policy" card → "Require Data Shield on every LLM node"Executor fails any run whose LLM nodes haven't opted in (DATA_SHIELD_POLICY_VIOLATION).
Per-packdata_shield_policy in the solution-pack manifestEvery workflow instantiated from the pack inherits the policy onto its activity row; authors can refine per-instance.

Kill switches (operators only — off by default)

VariableServiceEffect
DATA_SHIELD_DISABLED=truellm-serviceBypass the gateway entirely — raw payload reaches the LLM, no audit row. Incident response only.
DATA_SHIELD_AUDIT_DISABLED=truellm-serviceTokenise normally, skip the audit emit. Use only if the audit DB is the bottleneck.
DATA_SHIELD_AUDIT_RETENTION_DAYS=NDMSOverride the default 30-day retention on new audit rows.

Both kill switches are off in normal operation. Any period they are on is an attestation gap and must be logged in the operator runbook.

The 8 L1 entity types (always on when the shield is enabled)

TypeDetectionRegion
EMAILRFC-5322 subset regexInternational
PHONEE.164 + common US/UK/IN local formatsInternational
SSNUS SSN; rejects 000 / 666 / 9xx prefixesUnited States
CREDIT_CARD12–19 digits + Luhn validationInternational
IPIPv4 dotted quadInternational
AADHAAR12 digits + Verhoeff checksumIndia
PAN5 letters + 4 digits + letterIndia
IBANBasic IBAN structural checkInternational

L1 latency target: under 5 ms per request at the 95th percentile.

Tips & best practices

  • Require the policy on regulated workflows. Per-node opt-in is convenient but easy to forget; in insurance/legal/financial workflows set the Resilience-tab policy to required so a forgotten node fails the run loudly instead of leaking silently.
  • Review the audit log regularly. End users see their own activity at /account/activity; Super Admins search across tenants at /admin/audit. Use it to confirm the entity counts look right for each run (e.g. a customer-record agent should show non-zero EMAIL/PHONE). Rows are immutable and contain counts only — there are no raw values to leak.
  • Don't treat tokenisation as a PII classifier. Detectors are recall-biased: a 9-digit string that resembles an SSN may be tokenised even if it isn't one. "We tokenised it" means "candidate PII", not "this is definitely PII".
  • Know what v0.5 does NOT cover before signing anything: free-text names/locations/orgs, RAG chat, the public chatbot, Prompt Lab previews, file (file_urls) contents, multi-script / non-Latin PII, and any customer-held encryption key. See Limitations.
  • Tune retention to your obligations. The DS audit row default is 30 days — shorter than the rest of the audit log. Set DATA_SHIELD_AUDIT_RETENTION_DAYS to your record-keeping requirement.

Concrete examples

BEFORE / AFTER — what the provider sees vs. what the caller gets

The author sends a payload with PII. The provider only ever sees tokens; the caller gets the originals restored.

BEFORE (your payload)
  "Email jane.doe@acme.com or call +1-415-555-0142. SSN 086-12-3456."

WHAT THE LLM PROVIDER SEES (tokenised)
  "Email EMAIL_84d0a133 or call PHONE_1f9c2a07. SSN SSN_c95eb795."

AFTER (response restored to caller)
  "I have emailed jane.doe@acme.com and noted SSN 086-12-3456 on file."

Within this one call, jane.doe@acme.com always maps to EMAIL_84d0a133. In a different call the same address would map to a different token.

Enabling it on a node and requiring it on the workflow

  1. WorkflowBuilder → select the agent_task node → Data Shield card → flip the switch on. (Optional: in the chip row, restrict to EMAIL, PHONE, SSN only.)
  2. WorkflowBuilder → Resilience tab → Data Shield policy → "Require Data Shield on every LLM node."
  3. Any LLM node now left un-shielded makes the run terminate with DATA_SHIELD_POLICY_VIOLATION.

For a pack, declare it in the manifest instead so every instantiated workflow inherits it:

# solution-pack manifest
data_shield_policy:
  required: true
  entity_types: [EMAIL, PHONE, SSN, AADHAAR, PAN]

An audit-log entry (counts only — never raw values)

{
  "action": "data_shield.tokenise",
  "entity_counts": { "EMAIL": 1, "PHONE": 1, "SSN": 1 },
  "layers": ["L1"],
  "latencies_ms": { "tokenise_ms": 1, "roundtrip_ms": 1461 },
  "retention_days": 30,
  "correlation_id": "run_7af3c9e2",
  "provider": "claude",
  "model": "claude-opus-4-1"
}

There is no field anywhere in this row that holds jane.doe@acme.com or the SSN — only the count { "SSN": 1 }.

Dependencies

  • llm-service — hosts the tokenisation gateway and entry points (/api/v1/chat, /api/v1/extract).
  • DMS — audit log storage and retention; user activity view at /account/activity.
  • Workflow executor — enforces the per-workflow required policy.

Limitations (v0.5)

Data Shield v0.5 is deliberately narrow. The following are known gaps — read them before relying on it for a compliance attestation:

  • Free-text PII is not detected. Names, locations, organisations, narrative dates (PERSON / LOC / ORG) need L3 NER, which lands in v1.0. "Alice Johnson visited the New York office" reaches the LLM intact in v0.5 — only the 8 L1 types are caught.
  • RAG chat is not tokenised. Questions and retrieved context on the Knowledge Base / RAG path go to the LLM unmodified (v1.0).
  • Public chatbot and Prompt Lab previews are not covered — end-user messages and authored preview prompts reach the provider as-is.
  • File contents are not tokenised. file_urls are sent to the multimodal provider as-is; in-boundary OCR + pre-LLM tokenisation is a v1.0 deliverable.
  • Multi-script / non-Latin PII (Cyrillic, Han, Arabic, etc.) is not specifically detected.
  • Per-request scope only — no cross-call or cross-document persistence, and no customer-held key (both require the v1.0 KMS-backed scope).

Failure modes: detector error → fail-closed (HTTP 503); audit emit failure → fail-open; required-policy violation → workflow fails terminal; unknown token in the response → passed through untouched. See Troubleshooting.

Troubleshooting

SymptomCauseFix
LLM call returns 503, run blockedDetector errored at ingress (regex panic, unicode edge case). Data Shield is fail-closed — a missed PII check could be a breach, so it blocks rather than leak.Retry; if it persists, capture the input shape and report it. As a last resort an operator can set DATA_SHIELD_DISABLED (incident only — logs an attestation gap).
Run succeeded but no audit row appearedAudit emit failed (DMS down, JWT/network). Audit is fail-open — observability, not correctness — so the chat is preserved and a warning is logged.Check the llm-service warning log and DMS health; the LLM call itself was correct and shielded.
Workflow fails with DATA_SHIELD_POLICY_VIOLATIONThe workflow requires Data Shield on every LLM node, but one node hasn't opted in. The executor enforces the author's declared contract.Enable the Data Shield card on the flagged node, or relax the Resilience-tab requirement if the node genuinely needs no shield.
A token-shaped string appears in the final responseThe model invented a string matching our token pattern; Data Shield does not own it, so it is passed through untouched to avoid false substitution.Expected behaviour. If the model hallucinates tokens often, tighten the prompt.
Same value got a different token in another run / session"Deterministic within request scope" — consistency holds only inside one request's ephemeral map. Across requests, sessions, and tenants the same value deliberately maps to a different token.Expected in v0.5. Cross-call / cross-document consistency requires the v1.0 KMS-backed persistent scope.

How to test

  1. Enable on a node. In WorkflowBuilder, select an llm_task, open the Data Shield card, and flip the switch on.
  2. Run with sample PII. Execute it over text containing an email and an SSN, e.g. "Contact jane.doe@acme.com, SSN 086-12-3456."
  3. Confirm tokens reached the LLM. Inspect the run / provider request and verify the payload shows EMAIL_* and SSN_* tokens — not the raw values.
  4. Confirm values were restored. Verify the response handed back to the workflow contains the original jane.doe@acme.com and SSN.
  5. Inspect the audit log. At /account/activity confirm one data_shield.tokenise row with entity_counts: { EMAIL: 1, SSN: 1 }, layers: ["L1"], latencies, and a correlation id — and no raw values anywhere in the row.
  6. Verify the required policy. Set the workflow's Resilience-tab policy to required, leave a second LLM node opted out, run it, and confirm the run terminates with DATA_SHIELD_POLICY_VIOLATION.

Related pages

  • Governance — Data Shield is one of the platform's core governance controls.
  • Knowledge Base / RAG — note that RAG chat is NOT tokenised in v0.5; questions and retrieved context reach the LLM unmodified until v1.0.

Coming soon (forward-looking; not part of the v0.5 attestation):

CapabilityTarget
RAG chat, public chatbot, and Prompt Lab path coveragev0.6 / v1.0
In-boundary OCR + file-content tokenisationv1.0
Customer-held KMS key (Google CMEK first)v1.0
Persistent document scope (cross-document consistency)v1.0
L2 gazetteer + L3 NER (free-text names/locations/orgs)v1.0
Hash-chained evidence-pack export (signed PDF + JSON)v1.0
L4 commercial detector, L5 local-LLM detector, sensitivity-based routingv1.5

APIs used

MethodPathPurpose
POST/api/v1/chatDirect LLM chat (shielded)
POST/api/v1/extractStructured extraction (shielded)
(view)/account/activityUser's own tokenisation activity
(view)/admin/auditCross-tenant audit search (Super Admin)

See the synced Data Shield reference and architecture/data-shield/spec.md for the full spec.

On this page