Interface: DeidentifyReport
The audit trail returned alongside the de-identified dataset.
Every field except one is composed from static tables: tags, Part 6 keywords,
Annex E action codes, structural TAG[index] sequence paths, and registry
warning messages. uidMap is the exception, and it is not value-free. Its
keys are the source UIDs read out of the file, kept so a caller can make UID
replacement consistent across a study or an archive. A Study or SOP Instance
UID is a unique identifying number, so treat uidMap as PHI: the rest of the
report is safe to log, and that field is not.
Example
import { deidentify, parseDicom, type DeidentifyReport } from "@cosyte/dicom";
const { report }: { report: DeidentifyReport } = deidentify(parseDicom(buf));
console.log(report.attributes.length, "attributes acted on");
console.log(report.warnings.map((w) => w.code)); // e.g. burned-in annotation
Properties
attributes
readonlyattributes: readonlyDeidentifiedAttribute[]
Per-attribute outcomes for every attribute Annex E acted on.
embeddedAttributes
readonlyembeddedAttributes: readonlyEmbeddedAttributeFinding[]
Values emptied because whole Data Elements were encoded inside them by an over-declared Value Length. Empty on a well-formed file; a non-empty array means the source was malformed in a way that hid attributes from the action table, so treat it as a data-quality alarm on the sender as well as an audit line. See EmbeddedAttributeFinding.
removedPrivateTags
readonlyremovedPrivateTags: readonlystring[]
Private tags removed under the Basic Profile (kept ones are omitted).
retained
readonlyretained: readonlyDeidentifyOption[]
The Retain/Clean options that were active for this run.
uidMap
readonlyuidMap:ReadonlyMap<string,string>
Source UID → replacement UID, for cross-file consistency. The keys are document values, not composed identifiers: this is the one field of the report that carries PHI.
unauditableSequences
readonlyunauditableSequences: readonlyUnauditableSequenceFinding[]
SQ elements emptied because the parser did not materialize their items, so
the run had no Data Sets to walk and could not discharge PS3.15 §E.1.1's
obligation inside them. Empty on a well-formed file; a non-empty array means
content was dropped from the de-identified output, and the matching
DICOM_SQ_NOT_DESCENDED entry on Dataset.warnings says why the parse
refused. See UnauditableSequenceFinding.
Capped, and the cap is on the record only. A crafted input can carry
tens of thousands of un-auditable elements, so this array (and its matching
warnings) stops at MAX_UNAUDITABLE_SEQUENCE_FINDINGS. Every un-auditable
sequence is still emptied; an array exactly that long means "at least this
many", so read it as truncated rather than as a total.
It is not a complete list of what went un-audited, either: a private
SQ a Profile vouches for under RetainSafePrivate is kept
verbatim and never appears here.
undefinedVrElements
readonlyundefinedVrElements: readonlyUndefinedVrFinding[]
Elements emptied because their on-wire VR is not one of the 34 PS3.5 §6.2 defines, so their bytes are not a Value Field this library decoded and PS3.15 §E.1.1's obligation over what is inside them could not be discharged. Empty on a file conformant to PS3.5 2026c: a sender that writes one of the 34 VRs that edition defines never produces one, and an Implicit VR LE file cannot - there the VR comes from the dictionary. The edition is not pedantry: §6.2 exists precisely to say how a future VR will be encoded, so a file conformant to a later edition using a newly defined VR is the population that sentence exists for. (What such a file does on this library's parse path is not summarized here - it was measured and the shapes disagree.) A non-empty array means the source desynchronized the reader, usually by under-declaring a Value Length somewhere earlier. See UndefinedVrFinding.
Capped, and the cap is on the record only, exactly as
DeidentifyReport.unauditableSequences is: a crafted 1 MiB input can
carry over a hundred thousand such elements, so this array and its matching
warnings stop at MAX_UNDEFINED_VR_FINDINGS. Every one of them is still
emptied; an array exactly that long means "at least this many".
A finding here names a byte offset, not a tag - uniquely among the report's findings, and for a reason worth reading in UndefinedVrFinding: the tag of a fabricated header is itself part of some element's value.
Unlike its sibling this list has no carve-out, and the reason is
structural rather than a promise: keepOrEmpty is the only path that
writes a source value into de-identified output unchanged, and the test sits
at the top of it. Every other outcome - X remove, Z/C empty, D dummy,
U remap, and a private tag the Basic Profile drops - already replaces the
value. So a RetainSafePrivate element a Profile vouches for still
reaches this test and is still emptied, which is where the sibling
SQ-with-no-items rule has a real carve-out and this one does not.
warnings
readonlywarnings: readonlyDicomParseWarning[]
Safety warnings - notably burned-in-pixel annotation that cannot be cleaned.