Skip to main content
Version: v0.0.7

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

readonly attributes: readonly DeidentifiedAttribute[]

Per-attribute outcomes for every attribute Annex E acted on.


embeddedAttributes

readonly embeddedAttributes: readonly EmbeddedAttributeFinding[]

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

readonly removedPrivateTags: readonly string[]

Private tags removed under the Basic Profile (kept ones are omitted).


retained

readonly retained: readonly DeidentifyOption[]

The Retain/Clean options that were active for this run.


uidMap

readonly uidMap: 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

readonly unauditableSequences: readonly UnauditableSequenceFinding[]

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

readonly undefinedVrElements: readonly UndefinedVrFinding[]

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

readonly warnings: readonly DicomParseWarning[]

Safety warnings - notably burned-in-pixel annotation that cannot be cleaned.