Troubleshooting & Known Limitations
A value I expected to be transformed was blocked
That is the fail-closed rule working. The engine blocks (withholds the value, disposition
blocked) when it cannot confidently handle a locus: an unclassified PHI-bearing locus, an
unknown-kind locus, a free-text locus, a date/ZIP whose value it cannot generalize, or a policy
transform it cannot apply to that locus. The block is recorded in the manifest with
DEID_LOCUS_BLOCKED or DEID_FREETEXT_BLOCKED. It is never a silent pass-through of the value.
A keyed transform threw DEID_NO_KEY
Pseudonymize, keyed-hash, and date-shift are keyed. Supply a context
(createDeidContext({ key })) - the engine never falls back to an unkeyed transform, because an
unkeyed hash of an identifier is re-identifiable. Date-shift additionally needs a patientId scope.
deidentify threw EMPTY_INPUT
The model was null/undefined or carried no loci array. Pass { loci: [...] }.
The manifest is safe to log; the input is not
Manifest entries and error messages never contain PHI (no value, no key, no offset) - they are safe to log. Never log the input model or the raw document; it carries protected health information.
Known Limitations (this release - the format-agnostic core)
The library's promise is narrow and honest. Do not over-trust it:
- Not a certification. Output is "Safe-Harbor-transformed per the configured policy," never "de-identified" / "HIPAA-compliant". The actual-knowledge condition (§164.514(b)(2)(ii)) is the consumer's; Expert Determination is not rendered.
- The root entry is the generic core.
@cosyte/deiditself is the transform/policy/manifest core over a generic locus model, so the caller supplies each locus'spath,kind, andcategory. The per-format locus maps (HL7 v2, C-CDA, FHIR, X12, NCPDP, DICOM) - which is where "the parser knows where the name is" becomes automatic - live behind the matching subpath exports. - DOB vs. age is not linked in the core. Under the default policy a date generalizes to its
year, and a year is retained as a
DEID_RESIDUAL_RETAINEDresidual. A birth-date indicative of an age over 89 is not aggregated to90+by the generic core, because resolving DOB→age needs a reference date the core does not have. Surface the residual and apply the age-90 rule at the format layer (or via a profile) when a DOB is known to indicate age > 89. GEOGRAPHICis generalized as a ZIP. A locus of categoryGEOGRAPHICis treated as a ZIP code (initial-3-digit or000). Street/city/county elements should be removed - mark them for redaction (or a non-ZIP kind) rather than relying on ZIP generalization, which would keep a leading digit fragment (recorded as a residual, never silently). The per-format locus maps classify these precisely.- Free text is block-only. A
freetextlocus is blocked by default - no naive regex scrub (a false-safety hazard). A bring-your-own redaction interface is available via theredactoroption. - Date-shift is not Safe Harbor. It is an Expert-Determination-supporting mode; a shifted real date
is still a date. The
safe-harborpolicy generalizes dates to year instead.
The API Reference always reflects exactly what this release ships - treat it as the source of truth.