Pseudonymising CV + JD before any LLM call
A token-swap pipeline replaces every PII field with a deterministic stand-in before payloads leave our trust boundary. The model never sees a real name. Cost: ~80ms p95.
Context
Celer is a candidate-prep product. To do its job well it has to read your CV and the JD for the role you're targeting. Both documents are saturated with PII — names, employers, dates, addresses, the lot. Sending that to any LLM provider, even one we trust, opens a question we'd rather not be having on day one: where does this data go after it leaves us?
The default posture in the LLM-app world is to send the raw document and trust the provider's data-use terms. That position is defensible. It is not, however, the position we want to be in if a regulated buyer ever asks for a data-flow diagram.
Decision
A pseudonymisation gateway sits in front of every LLM call. Before the payload leaves our trust boundary:
- Named entities are detected (NER pass — names, organisations, dates, locations).
- Each entity is replaced with a deterministic token —
<PERSON_A>,<COMPANY_3>, etc. The map is stored server-side, keyed to the session. - The pseudonymised text is sent to the model.
- The model's response is rebound on the way back, replacing tokens with the original values.
The model only ever sees pseudonymised text. The mapping table never leaves our infrastructure.
Consequences
Cost. Roughly 80ms p95 added to every LLM call. Acceptable for everything that isn't strict real-time. The Live Conversational mode will need a lighter-weight pass.
Limits. Pseudonymisation is not redaction. The model still sees structure — that you used to work at some bank, that you went to some university. For most prep flows that's fine; for the rare regulated dataset we'd add a second redaction layer.
Posture. When a regulated client eventually asks "where does our user's data go", the answer is short. Pseudonymised text reaches the provider; full text never does. That's a one-line answer with a written ADR behind it.
Alternatives considered
- Self-hosting the model. Eliminates the question entirely. Tradeoff: cost and operational complexity well beyond what a single-operator product can sustain in 2026. Revisit when revenue warrants.
- Hashing instead of token-swap. Loses the ability to rebind responses cleanly — the model would speak in hashes. Token-swap costs the same and reads better in transcripts.
- Doing nothing. Defensible. Not the position we want to argue from.