Skip to main content

deidgate

Prove your PHI de-identification actually works — before the cloud LLM sees the data.

You told the security review "we de-identify PHI before it hits the model." deidgate is the test that proves it — on every deploy.

It runs a labeled, 100% synthetic HIPAA Safe Harbor corpus through your de-identification function and fails the build if any of the 18 identifiers survive. It runs entirely in your CI and never touches real PHI — so running it does not make you a Business Associate, and there's no BAA and nothing to procure.

pip install deidgate
# tests/test_deid.py
from deidgate import check_all
from myapp.deid import scrub          # <-- your de-identification, whatever it is

def test_deid_strips_all_phi():
    result = check_all(scrub)
    assert result.passed, result.summary()

or gate CI directly:

deidgate check --deid myapp.deid:scrub --md evidence.md   # exit 1 if anything leaks

Why this exists

Every guide says "de-identify first, then call the LLM." Almost nobody independently verifies the de-id works — they trust the vendor's accuracy number. But NLP de-id tops out around 90–99% recall and falls apart on real clinical text: dates written in prose, an MRN embedded mid-word, a reformatted SSN, an age over 89, a hyphenated surname, a nickname. One leak across the BAA boundary is a reportable event.

deidgate is a QA oracle, not another de-id model. Because the corpus is synthetic and labeled, it never has to detect PHI in unknown text (the hard problem everyone loses at). It only checks that each known planted identifier is gone — so the verdict is precise, deterministic, and auditable. It catches a leak three ways:

  • exact — the value survives verbatim
  • digits — a numeric identifier is reformatted but the digit run survives (123-45-6789 → 123456789)
  • split — a multi-token name/address survives with its distinctive tokens intact

What it covers

All 18 Safe Harbor identifiers (deidgate corpus lists them), including the adversarial cases naive pipelines miss:

Edge case Sample
Identifier in prose "admitted on the third of July… filed under mrn 2280"
Reformatted digits "SSN as written: 402 19 8877" (spaces, not dashes)
Age > 89 "a 94-year-old woman"
Embedded identifier "seen in clinic (chartMRN04857211)"
Hyphenated / misspelled name "Reyes-Villalobos, also charted as Reyes Villalobos"
Nickname "prefers to be called 'Sunny'"
City/county geo (no street) "resides in Tulare County near Visalia"

Try it against the deliberately-imperfect example de-id and watch it fail:

deidgate check --deid examples.naive_deid:naive_scrub
# FAIL — leaks across Safe Harbor categories: date, geo, mrn, ssn, ...

Audit evidence

--md evidence.md / --json evidence.json emits a per-element Safe Harbor pass/fail table you can drop into a validation record:

# deidgate Safe Harbor evidence — ✅ PASS
| # | Safe Harbor identifier            | Tested | Result |
| 1 | Names                             |   3    | ✅ pass |
| 3 | Dates (except year); ages > 89    |   4    | ✅ pass |
| 8 | Medical record numbers            |   3    | ✅ pass |
...

pytest integration

# pyproject.toml
[tool.pytest.ini_options]
deidgate_deid = "myapp.deid:scrub"
from deidgate import check_sample
def test_deid_leaves_no_phi(deidgate_deid, deid_sample):     # one test per corpus sample
    leaks = [l for l in check_sample(deidgate_deid, deid_sample) if not l.warning]
    assert not leaks, "; ".join(f"{l.cat.value}:{l.value!r}" for l in leaks)

Roadmap / commercial packs

The bundled corpus is a free starter set. Maintained adversarial edge-case packs (oncology notes, pediatric dates, i18n names, new LLM-jailbreak-style leaks), drift/canary monitoring, and one-click audit-evidence export are the paid tier — same --pack file.jsonl interface. Interested? → (landing page / waitlist link)

FAQ

  • Does it touch real PHI? No. The corpus is entirely synthetic — invented names, fake numbers. That's the point.
  • Is this legal or compliance advice? No. It's a testing tool; it gives you evidence, not an attestation.
  • What counts as "my de-id"? Any str -> str callable — a regex, a spaCy/Presidio pipeline, a call to a de-id API, whatever you run before the model.

MIT licensed.

Metadata

Release files for deidgate 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for deidgate 0.1.0
File Size Uploaded
deidgate-0.1.0.tar.gz 17.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for deidgate 0.1.0
File Interpreter ABI Platform
deidgate-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 34.6 kB

Release files / deidgate-0.1.0.tar.gz

Download URL deidgate-0.1.0.tar.gz
Size 17.4 kB
Tags Source
SHA-256 checksum
How to use checksums
d9117f7a4e8d750eec534caf1fa9818308f7f70df4d9cbddd2da46d7754b80bf
BLAKE2b-256 checksum
How to use checksums
6360d06b4f5d851030f6ad7e10b2fe6dc84df88eef6b79e03e31418747b5cbcb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / deidgate-0.1.0-py3-none-any.whl

Download URL deidgate-0.1.0-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
79e21c2dd9483560f7d3a0473c16a19a18f4b3b084f26dc6dc5b445f991ce39e
BLAKE2b-256 checksum
How to use checksums
b2f97c5065dced00f1533d28fce8fe04ac6aba8edad403f2db8e578af342a169
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page